点击上方亿元程序员+关注和★星标。
引言
Cocos中通过重写源码实现循环PageView
大家好,有小伙伴私信我:
“
有没有办法实现循环的PageView列表的方法呢
”
本文将介绍一下Cocos中通过重写源码实现循环PageView。
本文源工程可在文末阅读原文获取,小伙伴们自行前往。
1.什么是PageView
“
PageView 是一种页面视图容器.
”
我们接着来看看Cocos中的PageView
2.Cocos的PageView
PageView组件。
我们仔细看下编辑器,PageView主要有以下可视选项:
Inertia和Brake,是否开启滚动惯性和开启惯性后、在用户停止触摸后滚动多快停止,0表示永不停止,1表示立刻停止。
Elastic和Bounce Duration,是否允许滚动内容超过边界,并在停止触摸后回弹、回弹持续的时间,0 表示将立即反弹。
Content和Indicator,可滚动展示内容的节点、页面视图指示器组件。
Direction,页面视图滚动类型,包括水平和垂直。
PageEvents,滚动视图的事件回调函数。
下面一起来看看循环PageView的实现原理
3.循环PageView的实现原理
我们直接来看效果:
在最后一页向后翻页时回到第一页。
在第一页向前翻页时跳到最后一页。
下面一起来看看如何通过重写源码实现循环PageView
4.实现循环PageView
1.环境
引擎版本:Cocos Creator 3.8.1
编程语言:TypeScript
2.资源准备
本次效果节目组直接使用官方提供的组件,效果虽然不好看,但是靠谱。
结构大概如下。
仔细翻了一下,官方组件没有支持循环滚动,我们来稍稍修改一下。
3.编写代码
首先我们先找到官方的PageView源码。
笔者的目录在C:\ProgramData\cocos\editors\Creator\3.8.1\resources\resources\3d\engine\cocos\ui
小伙伴们可以通过CocosDashBoard,跳转到引擎目录后再寻找。
通过源码可以看到PageView组件继承ScrollView组件。
我们直接找到实现翻页的核心源码(为了方便大家阅读,加了一点点注释)。
/** * 自动滚动到页面的方法。 * 如果存在弹性回弹效果,将启动弹性回弹并根据边界的情况调整当前页面索引。 * 如果没有弹性回弹效果,根据触摸滑动的方向和速度来判断是否切换到相邻页面,并在合适的情况下执行页面切换。 * 最终会根据计算得到的目标页面索引,使用 scrollToPage 方法滚动到相应的页面。 */protected _autoScrollToPage(): void { // 检查是否启动弹性回弹效果 const bounceBackStarted = this._startBounceBackIfNeeded(); // 处理弹性回弹的情况 if (bounceBackStarted) { // 获取弹性回弹的偏移量 const bounceBackAmount = this._getHowMuchOutOfBoundary(); // 根据边界情况调整当前页面索引 this._clampDelta(bounceBackAmount); // 根据回弹方向调整当前页面索引 if (bounceBackAmount.x > 0 || bounceBackAmount.y < 0) { this._curPageIdx = this._pages.length === 0 ? 0 : this._pages.length - 1; } if (bounceBackAmount.x < 0 || bounceBackAmount.y > 0) { this._curPageIdx = 0; } // 如果存在指示器,通知状态变化 if (this.indicator) { this.indicator._changedState(); } } else { // 没有弹性回弹效果,处理手势滑动的情况 const moveOffset = new Vec2(); Vec2.subtract(moveOffset, this._touchBeganPosition, this._touchEndPosition); // 获取当前页面索引 const index = this._curPageIdx; // 计算下一个可能的页面索引 const nextIndex = index + this._getDragDirection(moveOffset); // 计算页面切换所需的时间 const timeInSecond = this.pageTurningSpeed * Math.abs(index - nextIndex); // 判断是否可以切换到相邻页面 if (nextIndex < this._pages.length) { if (this._isScrollable(moveOffset, index, nextIndex)) { // 执行页面切换 this.scrollToPage(nextIndex, timeInSecond); return; } else { // 判断是否可以快速滚动到相邻页面 const touchMoveVelocity = this._calculateTouchMoveVelocity(); if (this._isQuicklyScrollable(touchMoveVelocity)) { // 执行页面切换 this.scrollToPage(nextIndex, timeInSecond); return; } } } // 如果无法切换页面,则滚动回当前页面 this.scrollToPage(index, timeInSecond); }}
步骤一,我们新建一个CirculatePageView组件继承PageView组件用于重写核心源码实现循环滚动。
其中包含一个循环滚动的开关属性circulate。
import { _decorator, CCBoolean, PageView, Vec2 } from 'cc';const { ccclass, property } = _decorator;@ccclass('CirculatePageView')export class CirculatePageView extends PageView { @property({ type: CCBoolean, displayName: 'Circulate', tooltip: "是否循环" }) public circulate = true;}
步骤二,把PageView组件替换成我们自定义的CirculatePageView组件,并勾选Circulate循环滚动。
步骤三,将_autoScrollToPage方法拷贝到我们的自定义组件CirculatePageView中去进行修改重写,通过circulate属性取消回弹。
步骤四,插入自定义的代码,当开启循环滚动时,下一页nextIndex == -1时跳转到最后一页,下一页nextIndex == this._pages.length时跳转到第一页。(演示用,不做细节处理)
就这样我们就改写完成了,下面看看效果。
5.效果演示
结语
本文源工程可通过私信CirculatePageView获取。
在哪里可以看到如此清晰的思路,快跟上我的节奏!关注我,和我一起了解游戏行业最新动态,学习游戏开发技巧。
我是"亿元程序员",一位有着8年游戏行业经验的主程。在游戏开发中,希望能给到您帮助, 也希望通过您能帮助到大家。
AD:笔者线上的小游戏《贪吃蛇掌机经典》《重力迷宫球》《填色之旅》大家可以自行点击搜索体验。
实不相瞒,想要个赞和在看!请把该文章分享给你觉得有需要的其他小伙伴。谢谢!
推荐专栏:
100个Cocos实例
8年主程手把手打造Cocos独立游戏开发框架
和8年游戏主程一起学习设计模式
从零开始开发贪吃蛇小游戏到上线系列
知识付费专栏
点击下方绿色按钮+关注。