CocosCreator ScrollView无限滑动,支持指定从某个数据开始显示

本文介绍了如何在CocosCreator中实现ScrollView的无限滑动效果,并详细讲解了如何设置从特定数据开始显示的方法,提供排序脚本UIGrid和使用示例,帮助开发者实现更灵活的滚动界面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

废话不多说,直接上代码,原理看这边,看这边:https://blog.youkuaiyun.com/juedno/article/details/80767511
LoopScrow:

/**
 * 无限滑动组件
 * 注意点:
 * 1:无限滑动遵循横排竖滑,竖排横滑规则 即uigrid.arrangement 与ScrollView的滑动方向一定是相反的, 即:不支持横排横滑,竖排竖滑(有时候只需要横排排一排,然后横滑,必须改成竖排,限制uigrid.maxPerLine为1即可)
 * 2:不支持ScrollView.vertical 以及 不支持ScrollView.horizontal 同时为true  即不支持上下滑动的同时也可左右滑动  只支持一个方位
 * 3:uigrid排序组件是我仿照unity的ngui的uigrid排序组件写的 没有加入适配该节点的size大小,所以需要额外在挂载uigrid的节点上添加layout组件resizeMode设置为container type设置为none
 * 4:排序目前只支持TopLeft 即从左上角开始排序 (uigrid.pivot 会强制设置为Pivot.TopLeft)
 */
import { UIGrid, Pivot, Arrangement} from "./UIGrid";
const {ccclass, property} = cc._decorator;

@ccclass
export default class LoopScrow extends cc.Component
{
    @property({displayName: "排序组件UIGrid", type: UIGrid})
    public uiGrid: UIGrid | undefined = undefined; // 排序组件
    @property({displayName: "滑动组件ScrollView", type: cc.ScrollView})
    private scrowView: cc.ScrollView | undefined = undefined; // 滑动组件
    @property({displayName: "遮罩mask", type: cc.Mask})
    private mask: cc.Mask | undefined = undefined; // 遮罩
    @property({displayName: "生成的origiItem", type: cc.Prefab})
    private origiItem: cc.Prefab | undefined = undefined; // 原始item
    @property
    private itemCount: number = 0; // 需要初始化的item个数
    private extents!: number; // 所有预制体所占长度或者是高度的一半 用在循环的时候计算item的坐标
    private rows: number = 1; // 行数 (预制体所占的总行数)
    private columns: number = 1; // 列数 (预制体所占的总列数)
    private dataCount: number = 0; // 数据个数
    private cellWidth!: number; // 宽度间隔
    private cellHeight!: number; // 高度间隔
    private maxPerLine!: number; // 每行或者每列限制个数

    private maskSize!: cc.Size; // 遮罩组件的宽高
    private rightUpLocalPos!: cc.Vec2; // 遮罩右上局部坐标
    private leftDownLocalPos!: cc.Vec2; // 遮罩左下局部坐标
    private centerLocalPos!: cc.Vec2; // 遮罩中心点局部坐标
    private centerPos!: cc.Vec2; // 遮罩中心点世界坐标
    private _items!: cc.Node[]; // 需要生成的item数据
    public get items(): cc.Node[]{ return this._items; }
    private cacheContentPos!: cc.Vec2; // 缓存的内容坐标(重复设置数据的时候需要还原拉动的位置)

    /**
     * itemIndex: 需要渲染的item下标
     * dataIndex:需要渲染的数据下标
     * item: 需要渲染的item节点
     */
    private onRenderItem!: (itemIndex: number, dataIndex: number, item: cc.Node) => void; // 渲染回调
    public onLoad()
    {
        this.initObj();
        this.initMoveEvent();
        this.initMaskCornerLocalPos();
        this.initItems();
        if (this.scrowView != null)
        {
            this.cacheContentPos = this.scrowView.content.position;
        }
    }

    public start(): void
    {
        this.isUpdate = true;
    }

    private isUpdate: boolean = false;
    public lateUpdate(): void
    {
        if (this.isUpdate == true)
        {
            this.isUpdate = false;
            this.updateContentPos(this.cacheContentPos);
        }
    }

    /**
     * 初始化组件信息
     */
    private initObj(): void
    {
        if (this.uiGrid == null || this.scrowView == null)
        {
            return;
        }
        this.cellHeight = this.uiGrid.cellHeight;
        this.cellWidth = this.uiGrid.cellWidth;
        this.maxPerLine = this.uiGrid.maxPerLine;
        this.maskSize = this.scrowView.node.getContentSize();
        if (this.scrowView.horizontal == true && this.scrowView.vertical == true)
        {
            console.error("无限滑动组件不支持上下左右一起滑动");
            return;
        }

        if (this.scrowView.horizontal == true)
        {
            this.uiGrid.arrangement = Arrangement.Vertical; // 横排竖滑
            this.rows = this.maxPerLine;
            this.columns = this.itemCount / this.maxPerLine;
            this.extents = this.columns * this.cellWidth * 0.5;
        }else
        {
            this.uiGrid.arrangement = Arrangement.Horizontal; // 竖排横滑
            this.columns = this.maxPerLine;
            this.rows = this.itemCount / this.maxPerLine;
            this.extents = this.rows * this.cellHeight * 0.5;
        }
    }
    /**
     * 把遮罩的边角左边转换成content内的局部坐标
     * @param otherLocalPos
     */
    private convertCornerPosToContentSpace(otherLocalPos: cc.Vec2): cc.Vec2
    {
        let contentPos: cc.Vec2 = cc.Vec2.ZERO;
        if (this.mask == null || this.scrowView == null)
        {
            return contentPos;
        }
        const content: cc.Node = this.scrowView.content;
        const worldPos: cc.Vec2 = this.mask.node.parent.convertToWorldSpaceAR(otherLocalPos);
        contentPos = content.convertToNodeSpaceAR(worldPos);
        return contentPos;
    }
    /**
     * 初始化数据
     * @param dataCount 数据个数
     * @param onRenderItem 渲染回调
     */
    public initData(dataCount: number, onRenderItem: (itemIndex: number, dataIndex: number, item: cc.Node) => void): void
    {
        if (onRenderItem == null)
        {
            console.warn("无限滑动组件渲染回调没有注册事件");
        }
        this.onRenderItem = onRenderItem;
        this.dataCount = dataCount;
        this.onInitDatas();
        this.isUpdate = true;
    }
    /**
     * 当初始化数据的时候触发事件(第一次刷新所有的item数据)
     */
    private onInitDatas(): void
    {
        if (this.uiGrid == null || this.scrowView == null)
        {
            return;
        }
        if (this.cacheContentPos == null)
        {
            this.scrowView.scrollToOffset(cc.Vec2.ZERO);
            this.updateCacheContentPos();
        }else // 如果不是第一次设置数据 就需要还原滑动数据(位置要回归到最原始的状态)
        {
            this.scrowView.scrollToOffset(cc.Vec2.ZERO);
            this.scrowView.content.position = this.cacheContentPos;
        }
        for (let index = 0; index < this.itemCount; index++)
        {
            const item: cc.Node = this._items[index];
            const state: boolean = (index < this.dataCount);
            item.active = state;
        }
        this.uiGrid.reposition();
        for (let index = 0; 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值