【100个Cocos实例】通过重写源码实现循环PageView

引言

Cocos中通过重写源码实现循环PageView

大家好,有小伙伴私信我:

有没有办法实现循环的PageView列表的方法呢

本文将介绍一下Cocos中通过重写源码实现循环PageView

本文源工程可在文末阅读原文获取,小伙伴们自行前往。

1.什么是PageView

PageView 是一种页面视图容器.

我们接着来看看Cocos中的PageView

2.Cocos的PageView

PageView组件。

我们仔细看下编辑器PageView主要有以下可视选项:

  • InertiaBrake,是否开启滚动惯性和开启惯性后、在用户停止触摸后滚动多快停止,0表示永不停止,1表示立刻停止。

  • ElasticBounce Duration,是否允许滚动内容超过边界,并在停止触摸后回弹、回弹持续的时间,0 表示将立即反弹。

  • ContentIndicator,可滚动展示内容的节点、页面视图指示器组件。

  • 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组件。

我们直接找到 实现翻页的核心源码(为了方便大家阅读,加了一点点注释)。

typescript 复制代码
/**
 * 自动滚动到页面的方法。
 * 如果存在弹性回弹效果,将启动弹性回弹并根据边界的情况调整当前页面索引。
 * 如果没有弹性回弹效果,根据触摸滑动的方向和速度来判断是否切换到相邻页面,并在合适的情况下执行页面切换。
 * 最终会根据计算得到的目标页面索引,使用 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

typescript 复制代码
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年游戏主程一起学习设计模式

从零开始开发贪吃蛇小游戏到上线系列

知识付费专栏

相关推荐
YBN娜4 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=4 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck8 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!29 分钟前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。34 分钟前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼40 分钟前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui
k093344 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
EricWang13581 小时前
[OS] 项目三-2-proc.c: exit(int status)
服务器·c语言·前端
September_ning1 小时前
React.lazy() 懒加载
前端·react.js·前端框架
web行路人1 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架