Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

适配到3.x后CCMPicker滚动有问题,跟诡异,相见视频 #10

Open
shi-xintao opened this issue Oct 17, 2022 · 0 comments
Open

Comments

@shi-xintao
Copy link

shi-xintao commented Oct 17, 2022

2022-10-17.14.22.06.mov

适配到3.x后CCMPicker滚动有问题,CCMCategoryView没问题,相见视频。

跟进了一下,设置的index没问题了。

这是适配后的代码CCMPicker

import { _decorator, ScrollView, Component, Prefab, Layout, error, instantiate, v2, sys, Node, Touch, Vec3, v3, UITransform } from "cc";

const EPSILON = 1e-4;
const MINIMUM_VELOCITY = 30;

const { ccclass, property } = _decorator;

export interface Adapter {
    dataSource: any[],
    onPick?: (index: number) => void,
    bindView?: (node: Node, data: any, index: number) => void,
    transform?: (node: Node, ratio: number) => void
}

@ccclass
export class CCMPicker extends ScrollView {

    @property({
        override: true,
        visible: false
    })
    public horizontal: boolean = false;

    @property({
        override: true,
        visible: false
    })
    public vertical: boolean = true;

    @property({
        override: true,
        visible: false
    })
    public inertia: boolean = true;

    @property({
        override: true,
        visible: false
    })
    public elastic: boolean = true;

    @property({
        override: true,
        visible: false
    })
    public cancelInnerEvents: boolean = true;

    @property({
        override: true,
        visible: false
    })
    get verticalScrollBar(): any {
        return null;
    };

    set verticalScrollBar(scrollbar: any) {
        // nothing to do
    }

    @property({
        override: true,
        visible: false
    })
    get horizontalScrollBar(): any {
        return null;
    };

    set horizontalScrollBar(scrollbar: any) {
        // nothing to do
    }

    @property({
        override: true,
        visible: false,
        type: [Component.EventHandler]
    })
    public scrollEvents: any[] = [];

    @property(Prefab)
    private itemPrefab: Prefab = null;

    private itemHeight = 0;
    private currentIndex = 0;
    private hasLocated = false;
    private adapter: Adapter = null;

    private pickCallback = () => {
        if (!this.adapter || !this.adapter.onPick) return;
        this.adapter.onPick(this.getCurrentIndex());
    };

    public onLoad() {
        this.itemHeight = this.itemPrefab.data.getComponent(UITransform).height;
        var layout = this.content.getComponent(Layout);
        if (!!layout) {
            layout.paddingTop = (this.node.getComponent(UITransform).height - this.itemHeight) / 2;
            layout.paddingBottom = layout.paddingTop + this.content.parent.getComponent(UITransform).height - this.node.getComponent(UITransform).height;
        }
    }

    private getBaseline(): number {
        return - this.getScrollOffset().y - this.node.getComponent(UITransform).height / 2;
    }

    protected _moveContent(deltaMove: any, canStartBounceBack: boolean) {
        // @ts-ignore
        super._moveContent(deltaMove, canStartBounceBack);
        if (!this.adapter || !this.adapter.transform) return;
        let children = this.content.children;
        if (!children || !children.length) return;
        let baseline = this.getBaseline();
        for (let i = 0, ii = children.length; i < ii; i++) {
            let child = children[i];
            let offset = child.position.y - baseline;
            let ratio = offset / this.itemHeight;
            this.adapter.transform(child, ratio);
        }
    }

    public setAdapter(adapter: Adapter) {
        if (!adapter) {
            error('adapter can not be undefined!');
            return;
        }
        this.adapter = adapter;
        let { dataSource, bindView } = adapter;
        for (let i = 0, ii = dataSource.length; i < ii; i++) {
            let child = instantiate(this.itemPrefab);
            if (bindView) bindView(child, dataSource[i], i);
            this.content.addChild(child);
        }
    }

    // override disable wheel event
    protected _onMouseWheel() {
    }

    public setCurrentIndex(index: number) {
        this.currentIndex = index;
        this.hasLocated = true;
        let targetY = index * this.itemHeight;
        let offsetY = Math.abs(this.getScrollOffset().y);
        let deltaY = Math.abs(targetY - offsetY);
        let duration = Math.min(0.5 * deltaY / this.itemHeight, 0.8);
        console.log(`targetY:`, targetY)
        this.unschedule(this.pickCallback);
        this.scrollToOffset(v2(0, targetY), duration);
    }

    private scrollToClosestLocation() {
        let { y: currentOffset } = this.getScrollOffset();
        let remainder = currentOffset % this.itemHeight;
        let delta = Math.abs(remainder) > this.itemHeight / 2 ? (this.itemHeight - Math.abs(remainder)) : (-Math.abs(remainder));
        let targetOffset = currentOffset + delta;
        let duration = 0.5;
        this.hasLocated = true;
        this.scrollToOffset(v2(0, targetOffset), duration);
        let index = Math.round(Math.abs(targetOffset) / this.itemHeight);
        this.unschedule(this.pickCallback);
        if (this.currentIndex == index) return;
        this.currentIndex = index;
        this.scheduleOnce(this.pickCallback, duration);
    }

    protected _handleReleaseLogic(touch: Touch) {
        let vec2 = touch.getDelta();
        this._gatherTouchMove(v3(vec2.x, vec2.y));
        let bounceBackStarted = this._startBounceBackIfNeeded();
        if (!bounceBackStarted && this.inertia) {
            let velocity: Vec3 = this._calculateTouchMoveVelocity();
            let needFling = sys.OS.ANDROID == sys.os ? Math.abs(velocity.y) > MINIMUM_VELOCITY : !velocity.equals(v3(0, 0), EPSILON);
            if (needFling && this.brake < 1) {
                this.hasLocated = false;
                this._startInertiaScroll(velocity);
            } else if (this._touchMoved) {
                this.scrollToClosestLocation();
            }
        }
        this._onScrollBarTouchEnded();
        if (this._autoScrolling) return;
        this.scrollToClosestLocation();
    }

    private getCurrentIndex(): number {
        return this.currentIndex || 0;
    }

    private getCurrentData(): any {
        if (!this.adapter || !this.adapter.dataSource) return undefined;
        return this.adapter.dataSource[this.getCurrentIndex()];
    }

    protected _startAutoScroll(deltaMove, timeInSecond, attenuated) {
        let adjustedDeltaMove = this._flattenVectorByDirection(deltaMove);
        if (!this.hasLocated) {
            timeInSecond *= 0.2;
            let vec2 = this.getScrollOffset()
            let scrollOffset = v3(vec2.x, vec2.y);
            let autoScrollEndOffset = adjustedDeltaMove.add(scrollOffset);
            let remainder = autoScrollEndOffset.y % this.itemHeight;
            if (Math.abs(remainder) > this.itemHeight / 2) {
                adjustedDeltaMove.y += (this.itemHeight - Math.abs(remainder));
            } else {
                adjustedDeltaMove.y -= Math.abs(remainder);
            }
            let { y: offsetY } = adjustedDeltaMove.add(scrollOffset);
            let { y: maxoffsetY } = this.getMaxScrollOffset();
            if (offsetY < 0) {
                offsetY = 0;
            } else if (offsetY > maxoffsetY) {
                offsetY = maxoffsetY;
            }
            this.currentIndex = Math.round(Math.abs(offsetY) / this.itemHeight);
            this.unschedule(this.pickCallback);
            this.scheduleOnce(this.pickCallback, timeInSecond * 0.5);
        }
        this._autoScrolling = true;
        this._autoScrollTargetDelta = adjustedDeltaMove;
        this._autoScrollAttenuate = attenuated;
        this._autoScrollStartPosition = this.getContentPosition();
        this._autoScrollTotalTime = timeInSecond;
        this._autoScrollAccumulatedTime = 0;
        this._autoScrollBraking = false;
        this._isScrollEndedWithThresholdEventFired = false;
        this._autoScrollBrakingStartPosition = v3(0, 0);

        let currentOutOfBoundary: Vec3 = this._getHowMuchOutOfBoundary();
        if (!currentOutOfBoundary.equals(v3(0, 0), EPSILON)) {
            this._autoScrollCurrentlyOutOfBoundary = true;
            let afterOutOfBoundary = this._getHowMuchOutOfBoundary(adjustedDeltaMove);
            if (currentOutOfBoundary.x * afterOutOfBoundary.x > 0 ||
                currentOutOfBoundary.y * afterOutOfBoundary.y > 0) {
                this._autoScrollBraking = true;
            }
        }
    }

}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant