cocoscreator: 实现旋转循环页视图

circle3.gif

如上效果,本文实现一个类似旋转门的视图, 版本: 2.4.8

实现原理

1,初始化6个节点的属性信息_posInfos,如缩放,位置,透明度和层级

2,6张图片节点分别用_posInfos每个子项的数据进行初始化

3,每张图片节点设置一个可变的索引_index,左移的时候,_index--, 右移的时候,_index++, _index小于0时,设置成_posInfos.length-1, _index大于_posInfos.length-1,设置成0

4,节点根据_posInfos[_index]数据进行移动,移动期间会伴随缩放,透明度变化,层级改变

编辑器操作

1,首先在Canvas底下创建一个大小和Canvas一样的空节点cardNodes

image.png

2,在cardNodes底下添加6个子节点,card1-card6类型为Sprite,图片在Texture文件夹里

image.png

编写代码

创建RotateController.ts类,挂载到cardNods节点上,在initPosInfos方法中初始化6个节点位置的属性信息

// RotateController.ts

private _posInfos: PosInfo[];    
...

private initPosInfos(): void {
        this._posInfos = [
            {
                scale: 1,
                opacity: 255,
                zIndex: 1,
                pos: cc.v2(0, 0),
            },
            {
                scale: 0.8,
                opacity: 200,
                zIndex: 1,
                pos: cc.v2(400, 0),
            },
            {
                scale: 0.6,
                opacity: 100,
                zIndex: 0,
                pos: cc.v2(300, 0),
            },
            {
                scale: 0.5,
                opacity: 50,
                zIndex: 0,
                pos: cc.v2(0, 0),
            },
            {
                scale: 0.6,
                opacity: 100,
                zIndex: 0,
                pos: cc.v2(-300, 0),
            },
            {
                scale: 0.8,
                opacity: 200,
                zIndex: 1,
                pos: cc.v2(-400, 0),
            },
        ];
    }

这个配置其实分两层,上层索引值分别为5, 0, 1,层级为1,下层索引值为2, 3, 4,层级为0,层级越大,显示在上面,否则,显示在下面,在页面视图中,以上层的中心位置为第一个节点,并以逆时针方向依次增加索引。

PosInfo放在base.ts文件中

// base.ts
/** 每个位置的信息 */
export interface PosInfo {
    /** 位置 */
    pos: cc.Vec2;
    /** 缩放 */
    scale: number;
    /** 透明度 */
    opacity: number;
    /** 层级 */
    zIndex: number;
}

初始化各个图片节点的位置,缩放,透明度、层级和索引,这里通过类CardInfo控制图片的初始化和执行缓动动作

// RotateController.ts
...
private initNodes(): void {
    const children = this.node.children;
    for (let i = 0; i < children.length; i++) {
        const child = children[i];
        child.addComponent(CardInfo);
        const itemInfo = child.getComponent(CardInfo);
        itemInfo.initPosInfo(this._posInfos[i], i);
    }
}

// CardInfo.ts
/** 初始化 */
initPosInfo (posInfo: PosInfo, index: number): void {
    this.curInfo = posInfo;

    this.node.scale = posInfo.scale;
    this.node.opacity = posInfo.opacity;
    this.node.zIndex = posInfo.zIndex;
    this.node.x = posInfo.pos.x;
    this.node.y = posInfo.pos.y;

    this.index = index;
}

RotateController.tsonLoad调用上面初始化代码后,就可以监听活动事件

// RotateController.ts
onLoad () {
    // 初始化
    this.initPosInfos();
    this.initNodes();
    
    // 监听滑动事件
    this.node.on(cc.Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
}

滑动事件中,当滑动距离相对于起始点位置差值大于5时,为向右旋转,当滑距离相对于起始位置的差值小于-5,为向左旋转,由于滑动是个持续事件,因此如果图片节点已经执行了缓动动作,并且没有停止,这时触摸回调中应禁止响应新的缓动动作。

// RotateController.ts
private onTouchMove(event: cc.Event.EventTouch): void {
    /** 旋转没结束,不相应触摸 */
    for (let i = 0; i < this.node.children.length; i++) {
        const child = this.node.children[i];
        const itemInfo = child.getComponent(CardInfo);
        if (itemInfo.numOfRunningActions() > 0) {
            return;
        }
    }

    // 执行旋转动作
    const deltaX = event.getDelta().x;
    if (deltaX > 5) {
        this.rotateRight();
    } else if (deltaX < -5) {
        this.rotateLeft();
    }
}

/** 向左转 */
private rotateLeft(): void {
    const children = this.node.children;
    children.forEach((child, index) => {
        const itemInfo = child.getComponent(CardInfo);
        if (itemInfo.index > 0) {
            itemInfo.index--;
        } else {
            itemInfo.index = children.length - 1;
        }
        itemInfo.rotateAction(this._posInfos[itemInfo.index]);
    });
}

/** 向右转 */
private rotateRight(): void {
    const children = this.node.children;
    children.forEach((child, index) => {
        const itemInfo = child.getComponent(CardInfo);
        if (itemInfo.index < children.length - 1) {
            itemInfo.index++;
        } else {
            itemInfo.index = 0;
        }
        itemInfo.rotateAction(this._posInfos[itemInfo.index]);
    });
}

CardInfo控制着图片节点的缓动动作

/** 旋转到下一个位置,posInfo的数据 */
rotateAction (posInfo: PosInfo): void {
    if (this.curInfo === posInfo) {
        return;
    }        

    if (this._index === 5) {
        console.info("rotateAction", this._index, this.curInfo, posInfo);
    }

    cc.tween(this.node)
      .to(0.2, {x: posInfo.pos.x, scale: posInfo.scale, opacity: posInfo.opacity})
      .call(() => {
            this.node.zIndex = posInfo.zIndex;
      })
      .start();
}

/** 节点action的数量 */
numOfRunningActions (): number {
    return this.node.getNumberOfRunningActions();
}

到此编码结束,运行后就可以看到开篇的效果图。

全部评论

相关推荐

头像
不愿透露姓名的神秘牛友
03-20 10:18
点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务