// Learn TypeScript:
// - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
// - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class scrollView extends cc.Component {
/**显示区域 */
private mView:cc.Node;
/**承载区域 */
private mContent:cc.Node;
/**最大行数 根据宽高计算, 只有超出View时,向上取整 使得首尾可以兼顾 向上再取一个,防止出现空白*/
private mMaxRow:number=0;
/**是否开启滚动 */
private mIsOpenScroll:boolean=false;
/**最大列数 这个可以通过输入 或者传入决定 */
private mMaxVer:number=1;
/**最大替换的数量 */
private mMaxItemCount:number=0;
/**页面展示item的预制体元素 */
private mItemPrfab:cc.Prefab;
/**容器开始时的位置 */
private mContentStartY:number;
/**容器每次移动时的位置 */
private mContentCurY:number;
/**使用一个浮动指针,始终标记容器中显示在第一个节点的索引,
* 默认为0(的时候,向下滚动,会回弹,所以指针值不做改变,
* 值为最后一个数据节点索引时,向上滚动,会向下回弹,所以值也不做改变
* 浮标指针只是用来取list中的数据使用
* */
private mPointer:number=0;
private mListData:Array<any>=null;
/**item的组件 */
private mPfbComp:string=null;
onLoad () {
this.mView=cc.find("view",this.node);
this.mContent=cc.find("view/content",this.node);
this.mContentStartY=this.mView.height/2;
this.addEvent();
}
protected onDestroy(): void {
this.removeEvent();
}
private addEvent():void{
this.node.on('scrolling', this.scrolling, this);
}
private removeEvent():void{
this.node.off('scrolling', this.scrolling, this);
}
public init(list:any,pfb:cc.Prefab,comp:string,verCount:number=1):void{
this.mListData=list;
this.mItemPrfab=pfb;
this.mMaxVer=verCount;
this.mPfbComp=comp;
//计算最大行数
let needRow =Math.ceil(this.mListData.length/this.mMaxVer);
let needHeight =needRow*this.mItemPrfab.data.height;
if(needHeight>this.mView.height){
this.mIsOpenScroll=true;
}else{
this.mIsOpenScroll=false;
}
this.mMaxRow=Math.ceil(this.mView.height/this.mItemPrfab.data.height)+1;
this.mContent.height=needHeight;
this.mMaxItemCount=this.mMaxRow*this.mMaxVer;
this.initCount();
}
/**初始化容器节点 */
private initCount():void{
this.clearContent();
this.mPointer=0;
//根据列数,平分出N个单元。在每个单元中,将元素居中
let col =this.mContent.width/this.mMaxVer;
for(let i =0,varIndex=0;i<this.mMaxItemCount;i++,varIndex++){
if(i>=this.mListData.length)return;
varIndex%=this.mMaxVer;
let item =cc.instantiate(this.mItemPrfab);
this.mContent.addChild(item);
item.x= (varIndex+0.5)*col-this.mContent.width/2;
item.y=0-item.height*(Math.floor(i/this.mMaxVer)+0.5);
let data= this.mListData[i];
if(data){
item.getComponent(this.mPfbComp)?.setData(this.mListData[i]);
}
item.active=!!data;
}
}
/**刷新容器节点位置 */
private updataCount(changeY:number=0):void{
let children =this.mContent.children,len=children.length;
//显示区域的最顶层Y值
let showTopY =this.mItemPrfab.data.height*0.5;
//显示区域,最低层Y值
let showBootomY =showTopY-this.mItemPrfab.data.height*this.mMaxRow;
for(let i =0,varIndex=0;i<len;i++,++varIndex){
let child =children[i];
let sumY =child.y+changeY;
varIndex%=this.mMaxVer;
let data=null;
if(sumY>=showTopY){
data=this.mListData[(this.mMaxRow+this.mPointer-1)*this.mMaxVer+varIndex];
//上边的移到下面
if(data)child.getComponent(this.mPfbComp)?.setData(data);//
child.y-=this.mMaxRow*this.mItemPrfab.data.height;
child.active=!!data;
}
if(sumY<=showBootomY){
//下面的移到上面
data=this.mListData[this.mPointer*this.mMaxVer+varIndex];
child.y+=this.mMaxRow*this.mItemPrfab.data.height;
if(data)child.getComponent(this.mPfbComp)?.setData(data);
child.active=!!data;
}
}
}
private scrolling():void{
if(!this.mIsOpenScroll)return;
this.mContentCurY=this.mContent.y;
let changeY=this.mContentCurY-this.mContentStartY;
//改变值小于0,说明,在往下拉,会触发回弹 大于容器高度的时候 说明是向上拉,也会触发回弹
if(changeY<=0|| changeY>this.mContent.height-this.mView.height)return;
//计算出,上下浮动的几个item高度的单位 向下取整,说明,只有完全出去,才算是浮标指针改变,指向下一个
let pointCount =Math.floor(changeY/this.mItemPrfab.data.height) ;
this.mPointer=pointCount;
this.updataCount(changeY);
}
/**清理容器 */
private clearContent():void{
this.mContent.y=this.mContentStartY;
this.mContent.removeAllChildren();
}
}
纵向循环利用item ,优化scrollView