CCVirtualGridList - Cocos Creator 虚拟列表

一 控件介绍

CCVirtualGridList是基于Cocos Creator ScrollView + Layout 编写的一个具有虚拟布局特点的滚动列表控制容器。极其简洁,易用,支持平滑滚动显示大量数据对象,图片元素可以实现异步按帧加载,保证滚动平滑。具有滚动翻页功能,自适应宽度显示多列,单项选择,局部更新等实用功能。暂时只支持纵向滚动

Cocos Creator 引擎中提供了一个常规的滚动控制容器——ScrollView,实现基本滚动控制。但是缺少与之配合的List控件来实现虚拟布局功能,需要开发者手动扩展,在这里就提供一个实现虚拟布局功能的扩展列表控件,是参照Egret中的List控件的接口方式来实现。

二 虚拟布局原理

虚拟布局的原理其实很简单,就是只加载和显示可视区域的列表内容,可视区域外的并没有实体控件被实例化。以滚动事件驱动,动态滚动并复用可视区域内的列表模板,切换数据显示,看上去像一个完整的列表在上下滚动,由于此种设计实例化控件少,所以内存占用极少,drawcall数量低而且稳定,所以现在被普遍应用。但是虚拟布局的核心不仅在于此,由于需要不停地切换显示内容,如何将素材转换的更快速,更平滑才是虚拟列表的关键。CCVirtualGridList在VirtualGridListBaseItem 中提供自己的加载图片的方法——loadImage,实现异步按帧加载,保证列表滚动流畅度,又能有效利用缓存。

三 VirtualGridList 使用

使用控件非常简单,只需要拷贝demo项目中三个文件VirtualGridList.prefab,VirtualGridList.js,VirtualGridListBaseItem.js 到您的工程中Prefabs文件夹中即可。使用之前将VirtualGridList.prefab拖入画面中, 列表单元控制组件继承 VirtualGridListBaseItem 就可以。

四 API说明

##1 VirtualGridList 启动参数
启动参数可以在creator 图形化界面填入,但是为了不受预制体的维护影响,建议通过初 始化脚本接口传入启动参数。
virtualGridList.initGridList(itemTemplatePrefab, itemComponentName, options?)

参数

-itemTemplatePrefab    cc.Prefab   列表单元显示控件
- itemComponentName     String      列表单元显示控件控制器名称, 必须继承 VirtualGridListBaseItem
- options? {                     
    paddingTop?: Number             列表距离上边缘距离 默认为0
    paddingBottom?: Number          列表距离下边缘距离 默认为0
    spacingX?: Number               列间距 默认为3
    spacingY?: Number               行间距 默认为3
    columnNum?: Number              列数 默认为0,列数自动适配容器宽度
    useVirtualLayout?: Boolean        是否启用虚拟列表 默认为true
    emptyTip?: cc.String            没有数据显示提示
    cacheImage?: Boolean            通过virtualGridListBaseItem.loadImage()方法加载的
                                      图片,自动缓存,控件回收后,图片缓存将被全部释放。
}

##2 VirtualGridList 功能接口

createItemsDisplayList(dataList: any[]): void
首次创建显示列表, dataList为数据数组

appendItemsToDisplayList(dataList: any[]): void
追加显示列表, dataList为追加的数据数组,适用于滚动翻页

getDataList(): any[]
获取数据数组

getTemplateItems(): cc.Prefab[]
获取显示对象列表

clearList(): void
清空列表

findItemDisplayByData(data: any): cc.Prefab
根据数据对象查找对应的显示对象,当开启虚拟列表的时候,返回对象可能不存在

getImageFromCache(key: String): cc.Texture2D
获取缓存图片

addScrollToBottomEventHandler(handler: Function, thisObj: any): void
注册滚动至底部回调方法 当useVirtualLayout=false 时不可用

refreshItemDisplays(some?: any[]): void
修改数据后,刷新列表显示,some代表指定刷新的对象, 不传则刷新全部。

isTop(): Boolean
判断是否滚动至顶部

scrollToTop(): void
滚动至顶部

scrollToFixedPosition(itemIndex: Number, sec?: Number): void
滚动到固定位置 itemIndex代表滚动至指定显示对象的索引, sec为滚动动画时长

##3 VirtualGridListBaseItem 显示单元基类 (必须继承) 接口
data: any
数据对象。来自要显示的数据列表中的一条,每一条显示单元控件,都对应一条数据对象,当useVirtualLayout= true 的时候,单元控件对应的data数据对象不固定,会滚动切换。

dataChanged(): void
子类可覆盖方法,自定义显示方法,当滚动交替或初始化的时候触发。当useVirtualLayout= true 的时候,每一个显示单元控件都是滚动复用的,所以对应的Component组件也是复用的,所以不要在其内部记录与某一条数据对应的变量或属性。

dataChanged() {
        this._super();
        const data = this.data;
        this.loadImage(data.pic, this._showImg, this); // 建议所有图片通过loadImage加载,可以自动缓存,并且异步按帧加载,不卡顿
        this.lbItemName.getComponent(cc.Label).string = data.name;
        this.lbDate.getComponent(cc.Label).string = data.date;
    }

getItemIndex(): Number
获取现实对象在队列中的索引

onSelect(): void
子类可覆盖方法,点选触发事件,只支持单选

onUnselect(): void
子类可覆盖方法,如果当前为选中状态,当其他单元被点选触发此事件

onLeave(): void
子类可覆盖方法,当控件滑动离开可视区的时候触发 当useVirtualLayout=false 时不可用

onEnter(): void
子类可覆盖方法,当控件滑动进入可视区的时候触发 当useVirtualLayout=false 时不可用

loadImage(pic: String, cb: Function, thisObj: any): void
VirtualGridList 提供的异步加载图片, 自动缓存。pic: 图片地址, cb: 图片加载后的回调方法,thisObj: 回调方法this对象

五 简单demo

六 配合CCButtonDropdownList可以扩展实现带有虚拟布局的下拉列表

CCVirtualGridList 源码 + Demo

13赞

战略mark

感谢楼主,列表数量大几千的话,可以拖动旁边的scroll bar 来快速定位列表吗?

mask
安排上试试

mark

你想要的的功能从某种角度上与虚拟布局是有矛盾的,要想实现此功能,必须自定义一套滚动条控件。暂时还没有实现此功能,主要是针对移动端,scrollbar被忽略了。

此接口可以滚动到你想要的位置,但是滚动条这个真没有。

ts 项目中想试试这个插件,怎么调用到呢。 我没试出来呢。

heroItem.ts怎么引用到你那个BaseItem呢。 有没有 ts版本呢

1赞

我们自己封装的虚拟列表,只要数据是全的,就支持滚动条,而且支持每条item高度可变

mark

数据是全的话,滚动条好做,这个暂时设计目的是针对移动端,对滚动条要求不高

还没有实现ts版,可以试试,你再努力一下:blush:

牛,这个原生都不支持

正常是应该ts能直接引用到js的。 有试过的没

头部添加模块名,let VirtualGridListBaseItem = cc.Class({
底部输出模块,module.exports = VirtualGridListBaseItem;

试试看

支持横向的列表吗

mark

我用的就是这个方法


调用不到 dataChanged里的_super()

暂时不支持哦,不过也好写

ts访问父类方法写法好像不同,super.dataChanged(); 这样写如何?