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

原理看这边,看这边:https://blog.csdn.net/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; index < this.itemCount; index++)
        {
            const item: cc.Node = this._items[index];
            const dataIndex: number = this.getDataIndexByItemPos(item.position);
            if (item.active == true) // 只有当数据足够的时候才会触发渲染回调
            {
                this.updateItem(index, dataIndex, item);
            }
        }
    }
    /**
     * 初始化item
     */
    private initItems(): void
    {
        if (this.uiGrid == null || this.scrowView == null)
        {
            return;
        }
        this._items = [];
        const currentCount: number = this.uiGrid.node.childrenCount;
        const count: number = this.itemCount - currentCount;
        for (let index = 0; index < currentCount; index++)
        {
            const item = this.uiGrid.node[index];
            this._items.push(item);
        }
        for (let index = 0; index < count; index++)
        {
           const item: cc.Node = cc.instantiate(this.origiItem) as unknown as cc.Node;
           this._items.push(item);
           this.uiGrid.node.addChild(item);
        }
        this.uiGrid.start();
    }
    /**
     * 初始化移动事件
     */
    private initMoveEvent(): void
    {
        const eventHandle: cc.Component.EventHandler = new cc.Component.EventHandler();
        eventHandle.handler = "onScrowMove";
        eventHandle.component = "LoopScrow";
        eventHandle.target = this.node;

        if (this.scrowView == null)
        {
            return;
        }
        this.scrowView.scrollEvents.push(eventHandle);
    }
    /**
     * 初始化遮罩边角局部坐标
     */
    private initMaskCornerLocalPos(): void
    {
        if (this.mask == null)
        {
            return;
        }
        const halfHeight: number   = this.maskSize.height * 0.5;
        const halfwidth: number    = this.maskSize.width * 0.5;

        const minX: number         = this.mask.node.position.x - halfwidth; // 最小x
        const maxX: number         = minX + this.maskSize.width; // 最大x
        const minY: number         = this.mask.node.position.y - halfHeight; // 最小y
        const maxY: number         = minY + this.maskSize.height; // 最大y

        this.rightUpLocalPos    = new cc.Vec2(maxX, maxY); // 右上
        this.leftDownLocalPos   = new cc.Vec2(minX, minY); // 左下
        this.centerLocalPos     = (this.rightUpLocalPos.add(this.leftDownLocalPos));
        this.centerLocalPos.x   = this.centerLocalPos.x * 0.5;
        this.centerLocalPos.y   = this.centerLocalPos.y * 0.5;
    }

    /**
     * 初始化遮罩中心世界坐标
     */
    private getMaskCenterWorldPos(): void
    {
        this.centerPos = this.convertCornerPosToContentSpace(this.centerLocalPos);
    }
    /**
     * 滑动组件滑动事件回调
     */
    private onScrowMove(): void
    {
        this.getMaskCenterWorldPos();
        let item!: cc.Node;
        let localPos!: cc.Vec2;
        let distance: number = 0;
        let realIndex: number = 0;
        let newPos!: cc.Vec2;
        if (this.scrowView == null)
        {
            return;
        }
        if (this.scrowView.vertical == true)
        {
            for (let index = 0; index < this.itemCount; index++)
            {
                item = this._items[index];
                localPos = item.position;
                distance = localPos.y - this.centerPos.y;
                realIndex = 0;
                newPos = item.position;
                if (distance < -this.extents || distance > this.extents)
                {
                    if (distance < -this.extents)
                    {
                        newPos.y += this.extents * 2;
                    }else
                    {
                        newPos.y -= this.extents * 2;
                    }
                    realIndex = this.getDataIndexByItemPos(newPos);
                    if (realIndex >= 0 && realIndex < this.dataCount)
                    {
                        item.position = newPos;
                        this.updateItem(index, realIndex, item);
                    }
                }
            }
        }
        else
        {
            for (let index = 0; index < this.itemCount; index++)
            {
                item = this._items[index];
                localPos = item.position;
                distance = localPos.x - this.centerPos.x;
                realIndex = 0;
                newPos = item.position;
                if (distance < -this.extents || distance > this.extents)
                {
                    if (distance < -this.extents)
                    {
                        newPos.x += this.extents * 2;
                    }else
                    {
                        newPos.x -= this.extents * 2;
                    }
                    realIndex = this.getDataIndexByItemPos(newPos);
                    if (realIndex >= 0 && realIndex < this.dataCount)
                    {
                        item.position = newPos;
                        this.updateItem(index, realIndex, item);
                    }
                }
            }
        }
        // console.log(">>>>>>>>>>>>"+this.scrowView.getScrollOffset() + ">>>>>>>"+ this.scrowView.content.position + ">>"+this.mask.node.position);
    }
    /**
     * 刷新Item
     * @param itemIndex item下标
     * @param dataIndex  数据下标
     * @param item 需要渲染的item
     */
    private updateItem(itemIndex: number, dataIndex: number, item: cc.Node): void
    {
        if (this.onRenderItem != null)
        {
            this.onRenderItem(itemIndex, dataIndex, item);
        }
    }
    /**
     * 根据item的坐标来计算出对应的数据的下标
     * @param itemPos item的局部坐标
     */
    private getDataIndexByItemPos(itemPos: cc.Vec2): number
    {
        let dataIndex: number = 0;
        if (this.uiGrid == null)
        {
            return dataIndex;
        }
        let newPos: cc.Vec2 = new cc.Vec2(itemPos.x, itemPos.y);
        if (this.uiGrid.pivot != Pivot.TopLeft)
        {
            newPos = this.uiGrid.resetToTopLeftPos(newPos);
        }

        // 计算出行列数
        const x: number = newPos.x / this.cellWidth; // 行数
        const y: number = -newPos.y / this.cellHeight; // 列数
        if (this.uiGrid.arrangement == Arrangement.Horizontal)  // 横排
        {
            if (dataIndex != undefined)
            {
                dataIndex = x + y * this.maxPerLine;
            }
        }else // 竖排
        {
            dataIndex = y + x * this.maxPerLine;
        }
        return dataIndex;
    }
    /**
     * 刷新缓存content坐标
     */
    private updateCacheContentPos()
    {
        if (this.scrowView == null)
        {
            return;
        }
        this.cacheContentPos = this.scrowView.content.position;
    }
    /**
     * 刷新content坐标
     * @param newPos
     */
    public updateContentPos(newPos: cc.Vec2): void
    {
        if (this.scrowView == null)
        {
            return;
        }
        this.scrowView.scrollToOffset(cc.Vec2.ZERO);
        this.scrowView.content.position = newPos;
        this.updateCacheContentPos();
    }
    /**
     * 刷新排序组件锚点
     * @param pivot
     */
    public updateGridPivot(pivot: Pivot): void
    {
        if (this.uiGrid == null)
        {
            return;
        }
        this.uiGrid.updatePivot(pivot);
    }
    /**
     * 根据指定的数据下标来刷新列表
     * @param dataIndex 数据下标(范围:(0->dataCount-1))
     */
    public renderItemByIndex(dataIndex: number): void
    {
        if (dataIndex < 0)
        {
            dataIndex = 0;
        }
        else if (dataIndex >= this.dataCount)
        {
            dataIndex = this.dataCount - 1;
        }
        let currentColumns: number = 0; // 列数 从0开始
        let currentRows = 0; // 行数 从0开始
        let maxRows = 0; // 最大行数
        let maxColumns = 0; // 最大列数
        let posY = 0;
        let posX = 0;
        const showCountItem = this.rows * this.columns;
        if (this.scrowView == null || this.mask == null)
        {
            return;
        }
        if (this.scrowView.horizontal == true)
        {
            currentColumns = dataIndex / this.maxPerLine;
            maxColumns = (this.dataCount - 1) / this.maxPerLine;
            currentRows = dataIndex % this.maxPerLine;

            let startColumns = 0; // 开始的列数
            let offsetColums = 0; // 偏移的列数
            const maxShowColumns = Math.floor((this.mask.node.width / this.cellWidth));

            if (currentColumns + maxShowColumns / 2 < maxShowColumns)// 如果要显示的列数小于屏幕显示的最大列数 就直接从0列开始显示
            {
                startColumns = 0;
                offsetColums = startColumns;
            }
            else if (currentColumns + maxShowColumns / 2 >= maxColumns) // 如果当前显示的列数加上屏幕显示的最大列数大于最大的列数就从 最大列数-屏幕显示列数 开始显示
            {
                startColumns = maxColumns - this.columns + 1;
                offsetColums = maxColumns - maxShowColumns + 1;
            }
            else // 正常显示 这里可以改成- N
            {
                // (很多时候坑逼策划会让你居中显示, 下面代码可以改成 startColumns = currentColumns - (columns / 2) +1
                startColumns = currentColumns - 1;
                offsetColums = startColumns;
            }
            let line = -1;

            // 计算裁剪区域offset以及panel的坐标
            const offset: cc.Vec2 = new cc.Vec2((offsetColums) * this.cellWidth, 0);
            // let x = panel.transform.localPosition.x + panel.clipOffset.x;
            // panel.clipOffset = offset;
            // panel.transform.localPosition = new Vector3(x - offset.x, 0, 0);

            this.scrowView.content.x = this.cacheContentPos.x + offset.x;

            for (let i = 0; i < showCountItem; i++)
            {
                const item = this._items[i];

                if (i % this.rows == 0) // 下一列了
                {
                    line += 1;
                }
                const column = (startColumns + line);
                // if (column > maxColumns)
                // {
                //    break;//超标了 直接退出
                // }

                posX = column * this.cellWidth;
                posY = i % this.rows * - this.cellHeight;
                const newPos = new cc.Vec2(posX, posY);
                item.x = newPos.x;
                item.y = newPos.y;
                const realIndex = this.getDataIndexByItemPos(newPos);
                this.updateItem(i, realIndex, item);
            }
        }
        else
        {
            currentRows = dataIndex / this.maxPerLine;
            maxRows = (this.dataCount - 1) / this.maxPerLine;
            currentColumns = dataIndex % this.maxPerLine;

            let startRows = 0; // 开始的行数
            let offsetRows = 0; // 偏移的行数
            const maxShowRows = Math.floor((this.mask.node.height / this.cellHeight)); // 裁剪区域能显示的最大行数
            if (currentRows + maxShowRows / 2 < maxShowRows)//
            {
                startRows = 0;
                offsetRows = startRows;
            }
            else if (currentRows + maxShowRows / 2 >= maxRows)
            {
                startRows = maxRows - this.rows + 1;
                offsetRows = maxRows - maxShowRows + 1;
            }
            else
            {
                startRows = currentRows - 1;
                offsetRows = startRows;
            }
            let line = -1;

            // 计算裁剪以及panel的坐标
            const offset = new cc.Vec2(0, offsetRows * this.cellHeight);
            // let y = panel.transform.localPosition.y + panel.clipOffset.y;
            // panel.clipOffset = offset;
            // panel.transform.localPosition = new Vector3(panel.transform.localPosition.x, y - offset.y, 0);
            this.scrowView.content.y = this.cacheContentPos.y + offset.y;
            for (let i = 0; i < showCountItem; i++)
            {
                const item = this._items[i];
                if (i % this.columns == 0) // 下一行了
                {
                    line += 1;
                }
                const row = (startRows + line);
                if (row > maxRows)
                {
                    break; // 超标了 直接退出
                }
                posY = row * - this.cellHeight;
                posX = i % this.columns * this.cellWidth;

                const newPos = new cc.Vec2(posX, posY);
                item.x = newPos.x;
                item.y = newPos.y;
                const realIndex = this.getDataIndexByItemPos(newPos);
                this.updateItem(i, realIndex, item);
            }
        }
    }

    /**
     * 获取当前显示在第一个的渲染item(在显示区域看到第一个,如果是横滑则是看到的最左边那个item, 如果是竖滑则看到的是最上面的那个item)
     */
    public getFirstShowRenderItem(): cc.Node | null
    {
        if (this._items == null || this._items.length == 0){
            return null;
        }
        let localPos: cc.Vec2 = this._items[0].position;
        let distance: number = 0;
        let currentItemIndex: number = 0;
        for (let index = 1; index < this.itemCount; index++)
        {
            const item = this._items[index];
            distance = localPos.y - this.centerPos.y;
            if (distance >= -this.extents || distance <= this.extents)
            {
                if (this.scrowView != null)
                {
                    if (this.scrowView.horizontal == true)
                    {
                        if (item.position.x < localPos.x)
                        {
                            localPos = item.position;
                            currentItemIndex = index;
                        }
                    }else if (this.scrowView.vertical == true)
                    {
                        if (item.position.y < localPos.y)
                        {
                            localPos = item.position;
                            currentItemIndex = index;
                        }
                    }
                }
            }
        }
        return this._items[currentItemIndex];
    }
}


排序脚本UIGrid:
 

const {ccclass, property} = cc._decorator;

export enum Arrangement //排序枚举
{
    Horizontal = 1, //横排
	Vertical = 2, //竖排
}
export enum Pivot//锚点枚举
{
    TopLeft = 1, 
    Top = 2, 
    TopRight = 3,
    Left = 4,
    Center = 5,
    Right = 6,
    BottomLeft = 7,
    Bottom = 8,
    BottomRight = 9,
}
/**
 * 排序脚本
 */
@ccclass
export class UIGrid extends cc.Component {

    @property({type :cc.Enum(Arrangement),displayName:"排序枚举"})
    public arrangement:Arrangement = Arrangement.Horizontal; // 排序规则
    @property({type :cc.Enum(Pivot),serializable:true,displayName:"锚点枚举"})
    public pivot:Pivot = Pivot.TopLeft; //锚点
    @property
    public maxPerLine:number = 0; //行列个数
    @property
    public cellWidth:number = 100; //宽度
    @property
    public cellHeight:number = 100; //高度
    @property
    public hideInactive:boolean = false; //隐藏的item是否需要排序

    private mReposition:boolean = false; //
    /**
     * 排序回调
     */
    public onReposition:()=>void = null;
    /**
     * 重新排序
     */
    public set repositionNow(value:boolean)
    {
        if (value == true) 
        {
            this.enabled = true;
            this.mReposition = true;
        }
    }

    start () 
    {
        this.init();
        this.reposition();
        this.enabled = false;
    }
    /**
     * 初始化值
     */
    private init():void
    {
        this.maxPerLine = Math.floor(this.maxPerLine);
        this.arrangement = Math.floor(this.arrangement);
        this.pivot = Math.floor(this.pivot);
        
        if (this.arrangement > 2) 
        {
            this.arrangement = 2;    
        }else if (this.arrangement <= 0)
        {
            this.arrangement = 1
        }

        if (this.pivot > 9) 
        {
            this.pivot = 9;    
        }else if (this.pivot <= 0)
        {
            this.pivot = 1
        }
    }

    update (dt)
    {
        this.reposition();
        this.enabled = false;
    }

    /**
     * 获取子节点列表
     */
    public getChildList():cc.Node[]
    {
        let childCount:number = this.node.childrenCount;
        let childList:cc.Node[] = [];
        for (let index = 0; index < childCount; index++) 
        {
            let child :cc.Node= this.node.children[index]
            if (!this.hideInactive ||(child != null && child.active == true)) 
            {
                childList.push(child);
            }            
        }
        return childList;
    }
    /**
     * 根据下标来获取子节点
     * @param index 
     */
    public getChildByIndex(index:number):cc.Node
    {
        let childList:cc.Node[] = this.getChildList();
        return (childList.length > index)? childList[index]:null;
    }
    /**
     * 添加子节点node
     * @param child 
     * @param pos 
     */
    public addChild(child:cc.Node,pos?:cc.Vec2):void
    {
        child.parent = this.node;
        if (pos != null) 
        {
            child.position = pos;   
        }
    }
    /**
     * 重新排序(只有当node显示的时候调用才有效) 否则请调用repositionNow = true
     */
    public reposition ():void
    {
        let childList:cc.Node[] = this.getChildList();
        this.resetPosition(childList);
        if (this.onReposition != null) 
        {
            this.onReposition();    
        }
    }
    /**
     * 重新设置位置(排序)
     * @param childList 
     */
    private resetPosition(childList:cc.Node[]):void
    {
        this.mReposition = false;

        let x:number = 0;
        let y:number = 0;
        let maxX:number = 0;
        let maxY:number = 0;

        let length = childList.length;
        for (let index = 0; index < length; index++) 
        {
            let child:cc.Node = childList[index];
            let pos:cc.Vec2 = child.position;

            pos = (this.arrangement == Arrangement.Horizontal)? new cc.Vec2(this.cellWidth*x,-this.cellHeight*y):new cc.Vec2(this.cellWidth*y,-this.cellHeight*x);
            child.position = pos;

            maxX = Math.max(maxX,x);
            maxY = Math.max(maxY,y);
            if (++x>=this.maxPerLine &&this.maxPerLine > 0) 
            {
                x= 0;
                ++y;    
            }
        }
        if (this.pivot != Pivot.TopLeft)
        {
            let po:cc.Vec2 = this.GetPivotOffset(this.pivot);
            let fx,fy:number = 0;
            if (this.arrangement == Arrangement.Horizontal) 
            {
                fx = this.lerp(0,maxX*this.cellWidth,po.x);
                fy = this.lerp(-maxY*this.cellHeight,0,po.y);
            }else
            {
                fx = this.lerp(0,maxY*this.cellWidth,po.x);
                fy = this.lerp(-maxX*this.cellHeight,0,po.y);
            }
            for (let index = 0; index < length; index++) 
            {
                let child:cc.Node = childList[index];
                let pos:cc.Vec2 = child.position;
                
                pos.x -= fx;
                pos.y -= fy;
                child.position = pos;
            }
        }
    }   

    /**
     * 根据Item下标来获取该Item 排序之后所在的位置
     * @param itemIndex  从1 开始算
     */
    public getPreviewPostionByIndex(itemIndex:number):cc.Vec2
    {
        let chu:number = 0;
        let yu:number = 0;
        if (this.maxPerLine != 0) 
        {
            chu = itemIndex / this.maxPerLine;
            if (chu % this.maxPerLine != 0)
            {
                chu = Math.ceil(chu) - 1;
            }
            yu = itemIndex%(this.maxPerLine) - 1;
            if (yu < 0) 
            {
                yu = this.maxPerLine - 1;   
            }
        }
        else
        {
            chu = 0;
            yu = itemIndex - 1;
        }

        let row:number = 0;
        let column:number = 0;

        if (this.arrangement == Arrangement.Horizontal) 
        {
            row = chu;
            column = yu;
        }else
        {
            row = yu;
            column = chu;
        }
        let pos = cc.p((column )* this.cellWidth,(row)*-this.cellHeight); 

        // column = this.maxPerLine - 1; // 计算总列数(总行数)
        // row = Math.floor(this.node.children.length / this.maxPerLine);  //计算总行数(总列数)
        if (this.pivot != Pivot.TopLeft)
        {
            let maxX = this.maxPerLine - 1;
            let maxY = Math.floor(this.node.children.length / this.maxPerLine);
            if (this.maxPerLine != 0) 
            {
                maxX = this.maxPerLine - 1;
                maxY = Math.floor(this.node.children.length / this.maxPerLine);
            }else
            {
                maxX = this.getChildList().length - 1;
                maxY = 0;
            }
            let po:cc.Vec2 = this.GetPivotOffset(this.pivot);
            let fx,fy:number = 0;
            if (this.arrangement == Arrangement.Horizontal) 
            {
                fx = this.lerp(0,(maxX)*this.cellWidth,po.x);
                fy = this.lerp(-maxY *this.cellHeight,0,po.y);
            }else
            {
                fx = this.lerp(0,maxY*this.cellWidth,po.x);
                fy = this.lerp(-(maxX)*this.cellHeight,0,po.y);
            }
            pos.x -= fx;
            pos.y -= fy;
        }
        //console.log(pos.x+"ppppppppppppp<<<<<<"+pos.y +">>下标:"+itemIndex);
        return pos;
    }

    /**
     * 获取锚点偏移值
     * @param pv 
     */
    private GetPivotOffset (pv:Pivot):cc.Vec2
	{
		let v:cc.Vec2 = cc.Vec2.ZERO;

		if (pv == Pivot.Top || pv == Pivot.Center || pv == Pivot.Bottom) v.x = 0.5;
		else if (pv == Pivot.TopRight || pv == Pivot.Right || pv == Pivot.BottomRight) v.x = 1;
		else v.x = 0;

		if (pv == Pivot.Left || pv == Pivot.Center || pv == Pivot.Right) v.y = 0.5;
		else if (pv == Pivot.TopLeft || pv == Pivot.Top || pv == Pivot.TopRight) v.y = 1;
		else v.y = 0;
		return v;
    }
    /**
     * 计算插值
     * @param start 开始位置
     * @param end  结束位置
     * @param t  时间点
     */
    private lerp(start:number,end:number,t:number):number
    {
        let result = 0;
        if (t >1) {
            t = 1;
        }else if (t<0)
        {
            t = 0;
        }
        let tem = end - start;
        result = tem * t;
        result = result + start;
        return result;
    }
}

 

脚本使用示例

const {ccclass, property} = cc._decorator;

@ccclass
export default class LoopScrowTest extends cc.Component 
{

    @property(LoopScrow)
    loopScrow:LoopScrow= null; //无限循环组件
    private dataCount:number = 50;

    start () {
        let onRenderItem:any = (itemIndex:number,dataIndex:number,item:cc.Node)=>
        {
            if (this.dataCount<=dataIndex) 
            {
                return;
            }
            let label = item.getChildByName("Label").getComponent(cc.Label);
            label.string = (dataIndex+1).toString();
        }
        this.loopScrow.initData(this.dataCount,onRenderItem);
    }
}

挂载脚本关系:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值