cocosCreator2.x官方PageView组件升级版(支持显示多个和自由滑动)

const { ccclass, property, menu, executionOrder } = cc._decorator;

@ccclass
@menu('自定义组件/PageList')
@executionOrder(-100)
export default class PageList extends cc.Component {
    @property()
    private circulate = true;
    @property(cc.Node)
    tempItem: cc.Node = nn<cc.Node>();
    @property(cc.Node)
    slideParent: cc.Node = nn<cc.Node>();
    // 刷新某页信息
    @property(cc.Component.EventHandler)
    pageChangeEvent: cc.Component.EventHandler = new cc.Component.EventHandler();
    // 切换到某一页
    @property(cc.Component.EventHandler)
    pageRefreshEvent: cc.Component.EventHandler = new cc.Component.EventHandler();
    @property(cc.Integer)
    offset = 0;
    // 滑动距离与节点宽度比超过多少触发切换
    @property(cc.Float)
    switchPercent = 0.2;

    private isInit = false;
    private pageLeft: cc.Node = nn<cc.Node>();
    private pageRight: cc.Node = nn<cc.Node>();
    private pageCenter: cc.Node = nn<cc.Node>();

    private _curPageIndex = 0;
    private set curPageIndex(value: number) {
        this._curPageIndex = value;
        this.onRefreshPageIndex();
    }
    private get curPageIndex() {
        return this._curPageIndex;
    }
    private pageCnt = 0;
    private curTargetX = 0;
    private switchDistance = 0;
    override onLoad() {
        this.onInit();
    }

    onInit() {
        if (!this.isInit) {
            this.isInit = true;
            this.pageLeft = this.createPageItem();
            this.pageRight = this.createPageItem();
            this.pageCenter = this.tempItem;
            this.tempItem.active = false;
            this.switchDistance = this.node.width * this.switchPercent;
            this.registerEvent();
        }
    }

    createPageItem() {
        const node = cc.instantiate(this.tempItem);
        node.parent = this.slideParent;
        node.active = false;
        return node;
    }

    onRefreshList(showIndex: number, length: number) {
        if (showIndex >= length) {
            showIndex %= length;
        }
        this.pageCnt = length;
        this.curPageIndex = showIndex;
        this.slideParent.setPosition(0, 0);

        this.onRefreshPageInfo(this.pageCenter, showIndex);
        this.pageCenter.setPosition(0, 0);
        this.curTargetX = 0;
        const leftIndex = this.getLeftIndex(showIndex);
        if (leftIndex !== null) {
            this.onRefreshPageInfo(this.pageLeft, leftIndex);
            this.pageLeft.setPosition(-this.tempItem.width - this.offset, 0);
        } else {
            this.pageLeft.active = false;
        }
        const rightIndex = this.getRightIndex(showIndex);
        if (rightIndex !== null) {
            this.onRefreshPageInfo(this.pageRight, rightIndex);
            this.pageRight.setPosition(this.tempItem.width + this.offset, 0);
        } else {
            this.pageRight.active = false;
        }
        cc.Tween.stopAllByTarget(this.slideParent);
    }

    onRefreshPageInfo(target: cc.Node, index: number) {
        target.active = true;
        if (this.pageChangeEvent) {
            cc.Component.EventHandler.emitEvents([this.pageChangeEvent], target, index);
        }
    }

    onRefreshPageIndex() {
        if (this.pageRefreshEvent) {
            cc.Component.EventHandler.emitEvents([this.pageRefreshEvent], this.curPageIndex);
        }
    }

    private getLeftIndex(centerIndex: number) {
        let index = centerIndex - 1;
        if (index < 0 && this.circulate) {
            index = this.pageCnt - 1;
        }
        return index < 0 ? null : index;
    }
    private getRightIndex(centerIndex: number) {
        let index = centerIndex + 1;
        if (index >= this.pageCnt && this.circulate) {
            index = 0;
        }
        return index >= this.pageCnt ? null : index;
    }

    private touchStartX = 0;
    private contentStartX = 0;
    private touchFlag = false;
    private slideAnimation = false;
    onTouchStart(event: cc.Event.EventTouch) {
        if (this.slideAnimation) return;
        this.touchFlag = true;
        this.touchStartX = event.getLocationX();
        this.contentStartX = this.slideParent.x;
        this.isChanged = false;
    }
    private isChanged = false;
    private isChangeRight = false;
    onTouchMove(event: cc.Event.EventTouch) {
        if (!this.touchFlag) return;
        this.slideParent.setPosition(
            this.contentStartX + event.getLocationX() - this.touchStartX,
            0
        );
        const moveDistance = this.contentStartX - this.slideParent.x;
        if (
            Math.abs(moveDistance) >
            this.tempItem.width - (this.node.width - this.tempItem.width) / 2
        ) {
            if (!this.isChanged) {
                this.isChanged = true;
                if (moveDistance > 0) {
                    this.isChangeRight = true;
                    this.onFocusRight();
                } else {
                    this.isChangeRight = false;
                    this.onFocusLeft();
                }
            }
            return;
        }
        if (this.isChanged) {
            this.isChanged = false;
            this.isChangeRight ? this.onFocusLeft() : this.onFocusRight();
        }
    }
    onTouchEnd() {
        if (!this.touchFlag) return;
        this.touchFlag = false;
        this.slideAnimation = true;
        const slideDistance = this.curTargetX - this.slideParent.x;
        if (Math.abs(slideDistance) >= this.switchDistance)
            if (slideDistance > 0 && this.pageRight.active) {
                this.onFocusRight();
            } else if (slideDistance < 0 && this.pageLeft.active) {
                this.onFocusLeft();
            }
        cc.tween(this.slideParent)
            .to(Math.abs(this.curTargetX - this.slideParent.x) / 1000, {
                x: this.curTargetX,
            })
            .call(() => {
                this.slideAnimation = false;
            })
            .start();
    }

    private onFocusRight() {
        this.curTargetX = this.curTargetX - this.tempItem.width - this.offset;
        const changeNode = this.pageLeft;
        this.pageLeft = this.pageCenter;
        this.pageCenter = this.pageRight;
        this.pageRight = changeNode;
        this.curPageIndex = this.getRightIndex(this.curPageIndex) || 0;
        const nextIndex = this.getRightIndex(this.curPageIndex);
        if (nextIndex !== null) {
            this.pageRight.setPosition(this.pageCenter.x + this.tempItem.width + this.offset, 0);
            this.onRefreshPageInfo(this.pageRight, nextIndex);
        } else {
            this.pageRight.active = false;
        }
    }

    private onFocusLeft() {
        this.curTargetX = this.curTargetX + this.tempItem.width + this.offset;
        const changeNode = this.pageRight;
        this.pageRight = this.pageCenter;
        this.pageCenter = this.pageLeft;
        this.pageLeft = changeNode;
        this.curPageIndex = this.getLeftIndex(this.curPageIndex) || 0;
        const nextIndex = this.getLeftIndex(this.curPageIndex);
        if (nextIndex !== null) {
            this.pageLeft.setPosition(this.pageCenter.x - this.tempItem.width - this.offset, 0);
            this.onRefreshPageInfo(this.pageLeft, nextIndex);
        } else {
            this.pageLeft.active = false;
        }
    }

    registerEvent() {
        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this, true);
        this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this, true);
        this.node.on(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this, true);
        this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this, true);
    }

    unregisterEvent() {
        this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this, true);
        this.node.off(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this, true);
        this.node.off(cc.Node.EventType.TOUCH_CANCEL, this.onTouchEnd, this, true);
        this.node.off(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this, true);
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值