废话不多说,直接上代码,原理看这边,看这边: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);
}
}