一 控件介紹
CCVirtualGridList是基于Cocos Creator ScrollView + Layout 編寫的一個(gè)具有虛擬布局特點(diǎn)的滾動(dòng)列表控制容器。支持平滑滾動(dòng)顯示大量數(shù)據(jù)對(duì)象,圖片元素可以實(shí)現(xiàn)異步按幀加載,保證滾動(dòng)平滑。具有滾動(dòng)翻頁功能,自適應(yīng)寬度顯示多列,單項(xiàng)選擇,局部更新等實(shí)用功能。
Cocos Creator 引擎中提供了一個(gè)常規(guī)的滾動(dòng)控制容器——ScrollView,實(shí)現(xiàn)基本滾動(dòng)控制。但是缺少與之配合的List控件來實(shí)現(xiàn)虛擬布局功能,需要開發(fā)者手動(dòng)擴(kuò)展,在這里就提供一個(gè)實(shí)現(xiàn)虛擬布局功能的擴(kuò)展列表控件,是參照Egret中的List控件的接口方式來實(shí)現(xiàn)。

二 虛擬布局原理
虛擬布局的原理其實(shí)很簡單,就是只加載和顯示可視區(qū)域的列表內(nèi)容,可視區(qū)域外的并沒有實(shí)體控件被實(shí)例化。以滾動(dòng)事件驅(qū)動(dòng),動(dòng)態(tài)滾動(dòng)并復(fù)用可視區(qū)域內(nèi)的列表模板,切換數(shù)據(jù)顯示,看上去像一個(gè)完整的列表在上下滾動(dòng),由于此種設(shè)計(jì)實(shí)例化控件少,所以內(nèi)存占用極少,drawcall數(shù)量低而且穩(wěn)定,所以現(xiàn)在被普遍應(yīng)用。但是虛擬布局的核心不僅在于此,由于需要不停地切換顯示內(nèi)容,如何將素材轉(zhuǎn)換的更快速,更平滑才是虛擬列表的關(guān)鍵。CCVirtualGridList在VirtualGridListBaseItem 中提供自己的加載圖片的方法——loadImage,實(shí)現(xiàn)異步按幀加載,保證列表滾動(dòng)流暢度,又能有效利用緩存。
三 VirtualGridList 使用
使用控件非常簡單,只需要拷貝demo項(xiàng)目中三個(gè)文件VirtualGridList.prefab,VirtualGridList.js,VirtualGridListBaseItem.js 到您的工程中Prefabs文件夾中即可。使用之前將VirtualGridList.prefab拖入畫面中, 列表單元控制組件繼承 VirtualGridListBaseItem 就可以。
四 API說明
1. VirtualGridList 啟動(dòng)參數(shù)
啟動(dòng)參數(shù)可以在creator 圖形化界面填入,但是為了不受預(yù)制體的維護(hù)影響,建議通過初 始化腳本接口傳入啟動(dòng)參數(shù)。
virtualGridList.initGridList(itemTemplatePrefab, itemComponentName, options?)
參數(shù)
- itemTemplatePrefab cc.Prefab 列表單元顯示控件
- itemComponentName String 列表單元顯示控件控制器名稱, 必須繼承 VirtualGridListBaseItem
- options? {
paddingTop?: Number 列表距離上邊緣距離 默認(rèn)為0
paddingBottom?: Number 列表距離下邊緣距離 默認(rèn)為0
spacingX?: Number 列間距 默認(rèn)為3
spacingY?: Number 行間距 默認(rèn)為3
columnNum?: Number 列數(shù) 默認(rèn)為0,列數(shù)自動(dòng)適配容器寬度
useVirtualList?: Boolean 是否啟用虛擬列表 默認(rèn)為true
emptyTip?: cc.String 沒有數(shù)據(jù)顯示提示
cacheImage?: Boolean 通過virtualGridListBaseItem.loadImage()方法加載的
圖片,自動(dòng)緩存,控件回收后,圖片緩存將被全部釋放。
}
2. VirtualGridList 功能接口
createItemsDisplayList(dataList: any[]): void
首次創(chuàng)建顯示列表, dataList為數(shù)據(jù)數(shù)組
appendItemsToDisplayList(dataList: any[]): void
追加顯示列表, dataList為追加的數(shù)據(jù)數(shù)組,適用于滾動(dòng)翻頁
getDataList(): any[]
獲取數(shù)據(jù)數(shù)組
getTemplateItems(): cc.Prefab[]
獲取顯示對(duì)象列表
clearList(): void
清空列表
findItemDisplayByData(data: any): cc.Prefab
根據(jù)數(shù)據(jù)對(duì)象查找對(duì)應(yīng)的顯示對(duì)象,當(dāng)開啟虛擬列表的時(shí)候,返回對(duì)象可能不存在
getImageFromCache(key: String): cc.Texture2D
獲取緩存圖片
addScrollToBottomEventHandler(handler: Function, thisObj: any): void
注冊(cè)滾動(dòng)至底部回調(diào)方法 當(dāng)useVirtualList=false 時(shí)不可用
refreshItemDisplays(some?: any[]): void
修改數(shù)據(jù)后,刷新列表顯示,some代表指定刷新的對(duì)象, 不傳則刷新全部。
isTop(): Boolean
判斷是否滾動(dòng)至頂部
scrollToTop(): void
滾動(dòng)至頂部
scrollToFixedPosition(itemIndex: Number, sec?: Number): void
滾動(dòng)到固定位置 itemIndex代表滾動(dòng)至指定顯示對(duì)象的索引, sec為滾動(dòng)動(dòng)畫時(shí)長
3. VirtualGridListBaseItem 顯示單元基類 (必須繼承) 接口
data: any
數(shù)據(jù)對(duì)象。來自要顯示的數(shù)據(jù)列表中的一條,每一條顯示單元控件,都對(duì)應(yīng)一條數(shù)據(jù)對(duì)象,當(dāng)useVirtualLayout= true 的時(shí)候,單元控件對(duì)應(yīng)的data數(shù)據(jù)對(duì)象不固定,會(huì)滾動(dòng)切換。
dataChanged(): void
子類可覆蓋方法,自定義顯示方法,當(dāng)滾動(dòng)交替或初始化的時(shí)候觸發(fā)。當(dāng)useVirtualLayout= true 的時(shí)候,每一個(gè)顯示單元控件都是滾動(dòng)復(fù)用的,所以對(duì)應(yīng)的Component組件也是復(fù)用的,所以不要在其內(nèi)部記錄與某一條數(shù)據(jù)對(duì)應(yīng)的變量或?qū)傩浴?/p>
dataChanged() {
this._super();
const data = this.data;
this.loadImage(data.pic, this._showImg, this); // 建議所有圖片通過loadImage加載,可以自動(dòng)緩存,并且異步按幀加載,不卡頓
this.lbItemName.getComponent(cc.Label).string = data.name;
this.lbDate.getComponent(cc.Label).string = data.date;
}
getItemIndex(): Number
獲取現(xiàn)實(shí)對(duì)象在隊(duì)列中的索引
onSelect(): void
子類可覆蓋方法,點(diǎn)選觸發(fā)事件,只支持單選
onUnselect(): void
子類可覆蓋方法,如果當(dāng)前為選中狀態(tài),當(dāng)其他單元被點(diǎn)選觸發(fā)此事件
onLeave(): void
子類可覆蓋方法,當(dāng)控件滑動(dòng)離開可視區(qū)的時(shí)候觸發(fā) 當(dāng)useVirtualList=false 時(shí)不可用
onEnter(): void
子類可覆蓋方法,當(dāng)控件滑動(dòng)進(jìn)入可視區(qū)的時(shí)候觸發(fā) 當(dāng)useVirtualList=false 時(shí)不可用
loadImage(pic: String, cb: Function, thisObj: any): void
VirtualGridList 提供的異步加載圖片, 自動(dòng)緩存。pic: 圖片地址, cb: 圖片加載后的回調(diào)方法,thisObj: 回調(diào)方法this對(duì)象
五 顯示列表
initGridList(){
this._gridListController.initGridList(this.itemTemplate, 'ItemDisplayController', {
paddingTop: 10,
paddingBottom: 100,
spacingY: 5,
emptyTip: '什么也沒有啊',
columnNum: this._currentColumn,
useVirtualList: true
});
this._gridListController.addScrollToBottomEventHandler(this._nextPage, this); //注冊(cè)翻頁事件
this._showList();
},
showList(pageNo, itemCount) {
pageNo = pageNo || 1;
itemCount = itemCount || 29;
let list = [];
let total = pageNo * itemCount;
let picIndex = 0;
for (let i = (pageNo - 1) * itemCount + 1; i <= total; i++) {
picIndex++;
let item = {
pic: "avatar/avatar_" + picIndex,
date: "3/9 12:00",
name: i + '_測試郵件'
}
list.push(item);
}
this._dataList = this._dataList ? this._dataList.concat(list) : list; // 滾動(dòng)翻頁需要合并數(shù)據(jù)數(shù)組
this._gridListController.appendItemsToDisplayList(list);
}


