使用场景
游戏中经常会做列表类型的功能,例如游戏记录、排行榜,涉及到的数据很多,如果使用自带的ScrollView,会需要创建很多列表项组件,效率会很低,也很影响性能,由于工作中使用到的比较多,就封装了一个组件ListComponent,大致实现原理如下:
- 在列表可见区域内,创建列表项Unit,列表项多余可见区+1;
- 设置需要更新的数据,保存在组件内,一开始从第一条开始显示,直到显示能显示的列表项;
- 滑动列表项,更新不断的更改列表项的位置和内容,从而实现滑动的效果。
存在问题
也有一些问题,如:
- 滑动太快会不流畅,所以组件内取消了弹性功能;
- 进度条的长度动态计算没有加入,所以取消了进度条的显示;
组件使用
具体使用步骤如下:
- 把ListComponent挂在到ScrollView组件上,如下图所示:
- 列表项的预制和列表项预制上负责更新的脚本名称设置好;
- 预制脚本需要添加reloadUI(data:any)方法,为了更新UI。
下图就是挂在脚本的效果:
下图是自己项目的更新UI的函数:
这里根据自己的需要更新UI就行,传进来的data是一个对象类型的数据结构。
功能模块使用起来也很简单,如ScrollView组件的名称为list,使用方法如下:
let data = [{name:'aa', age:1}, {name:'bb', age:2}];
let listCom = list.getComponent('ListComponent');
listCom .reloadData(data);
listCom reloadUI();
最终实现效果如下图:
// Learn TypeScript:
// - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/typescript.html
// - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/typescript.html
// Learn Attribute:
// - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/reference/attributes.html
// - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
// - [Chinese] https://docs.cocos.com/creator/manual/zh/scripting/life-cycle-callbacks.html
// - [English] http://www.cocos2d-x.org/docs/creator/manual/en/scripting/life-cycle-callbacks.html
const {ccclass, property} = cc._decorator;
@ccclass
export default class ListComponent extends cc.Component {
@property(cc.Prefab)
prefabUnit: cc.Prefab = null;
@property
UnitComName: string = '';
private mData: Array<any> = [];
private mUnitHeight: number = 0;
private mMaxCount: number = 0;
private mCells: Array<any> = [];
private mIdx: number = 0;
private mOnBounceBottomCallback: any = null;
private mOnUnitClickCallback: any = null;
private mInited: boolean = false;
// LIFE-CYCLE CALLBACKS:
// onLoad () {}
start () {
}
// update (dt) {}
reloadData(data: Array<any>){
this.mData = data;
}
reloadUI(){
if(!this.mInited){
this.initScrollView();
this.addPrefab();
this.mInited = true;
}
this.reload();
}
setOnBounceBottomCallback(callback: any){
this.mOnBounceBottomCallback = callback;
}
setUnitClickCallback(callback: any){
this.mOnUnitClickCallback = callback;
}
initScrollView(){
if(this.prefabUnit == null){
return;
}
let scrollView = this.node.getComponent(cc.ScrollView);
if(scrollView == null){
return;
}
scrollView.inertia = false;
this.mUnitHeight = this.prefabUnit.data.height;
this.mMaxCount = Math.floor(scrollView.node.height / this.mUnitHeight) + 2;
if(this.mData.length > this.mMaxCount){
scrollView.content.height = this.mMaxCount * this.mUnitHeight;
}else{
scrollView.content.height = this.mData.length * this.mUnitHeight;
}
scrollView.node.on("scrolling", this.onScrolling, this);
scrollView.node.on("bounce-bottom", this.onBounceBottom, this);
scrollView.scrollToTop(0);
}
addPrefab(){
let scrollView = this.node.getComponent(cc.ScrollView);
if(scrollView == null){
return;
}
this.mCells = [];
scrollView.content.removeAllChildren();
for(let i = 0; i < this.mMaxCount; i++){
let node = cc.instantiate(this.prefabUnit);
scrollView.content.addChild(node);
node.x = node.width * (node.anchorX - 0.5);
node.y = -node.height * (1 - node.anchorY) - node.height * i;
this.mCells.push(node);
let js = node.getComponent(this.UnitComName);
if(js != null && js.registClickCallback != null){
js.registClickCallback((idx, node) => {
this.onUnitClick(idx, node)
});
}
}
}
onUnitClick(idx:number, node: cc.Node){
if(this.mOnUnitClickCallback != null){
this.mOnUnitClickCallback(idx, node);
}
}
onScrolling(event){
let offset = event.getScrollOffset();
if(offset.y <= 0 && this.mIdx > 0){
// 上移一格
offset.y += this.mUnitHeight;
event.scrollToOffset(offset);
// 更新数据
this.mIdx--;
this.reload();
}
else if(offset.y >= event.getMaxScrollOffset().y && (this.mIdx < this.mData.length - this.mMaxCount)){
// 下移一格
offset.y -= this.mUnitHeight;
event.scrollToOffset(offset);
// 更新数据
this.mIdx++;
this.reload();
if(this.mIdx == this.mData.length - this.mMaxCount - 1){
this.onBounceBottom(null);
}
}
}
onBounceBottom(event){
if(this.mOnBounceBottomCallback != null){
this.mOnBounceBottomCallback();
}
}
reload(){
for(let i = 0; i < this.mCells.length; i++){
this.mCells[i].active = (i < this.mData.length);
this.reloadCell(this.mIdx + i, this.mCells[i]);
}
}
reloadCell(idx, scrollViewCell){
if(idx < 0 || idx >= this.mData.length){
return;
}
if(scrollViewCell == null || this.UnitComName == ''){
return;
}
let UnitCom = scrollViewCell.getComponent(this.UnitComName);
if(UnitCom != null && UnitCom.reloadUI != null){
UnitCom.reloadUI(this.mData[idx]);
scrollViewCell.attr({_idx_: idx});
}
}
}
来源:CSDN
作者:^随风~~
链接:https://blog.csdn.net/ccnu027cs/article/details/103556717