Laya FairyGui系列八 GList

列表(GList)

游戏开发过程中经常会用到列表组件,比如我们做排行榜,服务器列表等。FGUI的列表能实现很多种复杂效果,相比较会比Laya原生的列表要强大。FGUI的虚拟列表还可以很好的处理数据量比较大的列表。

列表的基本用法很简单,还是一样点击左边工具栏上的列表按钮创建一个列表,列表很多时候里面显示的Iiem是差不多的,就是里面的图标换一下或者文本内容换一下啦,前面说GButton的时候也又提到过,列表的item使用的是GButton。这里设置列表的Item组件。


GList_0.png
  • 渲染顺序(列表是特殊容器,Item是列表的子节点,多个Item就有渲染顺序的问题,谁显示再前面谁显示再后面):

    • 升序 按照Item索引升序排列
    • 降序 按照Item索引降序排列
    • 拱形 自定义个显示再最前面的item,如果指定的是5,那么列表中第6个就显示在最前面。


      GList_3.png
  • 边缘 设置Item在列表中的位置

  • 触摸滚动效果 可以关闭列表滚动功能

为什么会是使用GButton呢,比如我们再做一个背包界面,每个物品都是一个背景,Icon,文本组成,这不是和GButton正好一样么,背包里面的物品需要点击GButton也支持。当然了,你一定不想用GButton,一定要用其他的也是可以的。
关于列表的属性有很多,我就不一一介绍了还是看官网

列表的使用

  • 添加列表Item
const listItem = fairygui.UIPackage.createObject("Package1",'listItem2').asButton;
listItem.title = "第6个";
testList.addChild(listItem);
  • 通过FGUI URL添加列表Item
const listItem2 =  testList.addItem("ui://Package1/listItem2").asButton;
listItem2.title = "第7个";
  • 删除列表Item
testList.removeChild(listItem2);
testList.removeChildAt(0);

当你对列表进行增加删除或者修改操作后,列表的排列和刷新是自动的,不需要调用任何API。

  • 获取列表中Item个数
// 获取列表中Item个数
console.log('numChildren = ' + testList.numChildren); //numChildren = 7
//获取列表中数据个数
console.log('numItems =' + testList.numItems); // numItems =7

在列表中Glist.numChildren永远是等于Glist.numItems的,后面说到的虚拟列表就不一定了。

  • 点击列表内的某一个item触发事件
testList.on(fairygui.Events.CLICK_ITEM,this,this.onClickItem)

private onClickItem(item:fairygui.GComponent,event:any){
    const itemButton = item.asButton;
    console.log('点击了' + itemButton.title + 'Button');
}

我们在开发排行榜时列表的内容会频繁的的更新,一般时从后台接受到数据后先清空列表,然后重新添加新的项目。但是会对象频繁的创建销毁会消耗很多的内存和CPU。因此列表内建了对象池解决这个问题。
使用对象池管理item的相关方法:

//从对象池中添加一个item到列表中,这里我们不用管对象池中有没有item,如果对象池时空的会fgui会自动帮我们创建
const listItem0 =  testList.addItemFromPool("ui://Package1/listItem2").asButton;
listItem0.title = '第1个';    
const listItem1 =  testList.addItemFromPool("ui://Package1/listItem2").asButton;
listItem1.title = '第2个';    
const listItem2 =  testList.addItemFromPool("ui://Package1/listItem2").asButton;
listItem2.title = '第3个';
const listItem3 =  testList.addItemFromPool("ui://Package1/listItem2").asButton;
listItem3.title = '第4个';    

// 将Item从列表中移除并放回对象池
testList.removeChildToPool(listItem1);
// 将指定位置的Item从列表中移除并放回对象池
testList.removeChildToPoolAt(0);
// 将指定范围内的Item从列表中移除并放回对象池,也可以移除全部(如果结束位置的索引小于0或者大于Item数量则移除全部)
testList.removeChildrenToPool(0,3);

虚拟列表

前面说到了FGUI可以很好的处理数据量很大的情况,试想一下玩家在第一次打开排行榜,这时候排行榜中有100条排名信息,如果我们不用循环的方式怎么将数据显示到item上呢,列表会有一个item渲染的回调函数,每一个item再被创建时都会将item对象传到回调函数中,我们可以再回调函数中进行数据和UI的绑定。

//设置列表的渲染回调
testList.itemRenderer = Laya.Handler.create(this,this.renderItem,null,false)
//在设置列表要显示的item数量(注意,这里一定要先设置渲染回调再设置item数量)
testList.numItems= 100;

private renderItem(index:number,item:fairygui.GComponent){
    //可以再这里将排行榜数据显示到item中
    const itemButton = item.asButton;
    itemButton.title = '第' + index + '个';
    console.log('item个数:' + item.parent._children.length);
}
GList_4.png

通过打印看到创建了100个item。
那么就算使用对象池也需要创建100个Item对象,这个开销也是很可怕的,关键是这100个item并不是每一个会都被玩家看到,可能玩家只会关心排名靠前的几个,那么后面的很多创建出来就是浪费的。
虚拟列表的处理方法是不管有多少个数据,始终只会创建出能在列表中显示出来的数量,在玩家滚动列表时动态设置数据。
说了这么多,其实我们只要再上面代码中设置渲染回调函数设置之前加上一句话就行了。

//开启虚拟列表
testList.setVirtual();
GList_5.png

再看下打印只创建了6个Item对象。只有6个Item是怎么显示100条排行榜信息呢。刚才的回调函数里面还有一个参数index这个时候就要用到了。
如果我们100条数据保存再一个数组里面。这6条item也是保存再数组里面,这里就有两个索引了

  • ItemIndex 对应着100条排行信息的索引
  • ChildIndex 对应着6个item对象的索引
    这两个索引有着一个转换接口:
    //根据itemIndex获取ChildIndex
    const childIndex = testList.itemIndexToChildIndex(index);
    //根据ChildIndex获取itemIndex
    const itemIndex = testList.childIndexToItemIndex(childIndex);

上面说到的回调函数中的index就是ItemIndex。然后根据这个index就可以从100条数据中取出应该现在再这个item上的数据了。
有些时候可能会有这个需求,玩家打开排行榜之后列表需要直接定位到自己的排名信息。

//假设玩家自得排名再第80名
const itemindex = 79
//滚动到指定的item,这里的参数应是itemIndex
testList.scrollToView(itemindex);
const childIndex = testList.itemIndexToChildIndex(itemindex);
// 这就是玩家自己排名信息得item
const item = testList.getChildAt(childIndex);

某些情况下可能不想让整个item接受点击事件,会再item内部放一个按钮让这个按钮响应点击事件,那么上面说到得按钮点击事件可能就不行了,这时候可以在渲染函数中设置点击事件。但是觉得不可以用匿名函数或者lamba表达式。否则会造成点击事件多次触发。

    //这里因为onClick事件是从Laya中触发,
    //在点击的回调函数中不能取到GButton对象,只能够取到GButton._displayObject。
    //所以这里将GButton对象作为参数传递到回调函数中
    itemButton.onClick(this,this.onClickItem,[itemButton]);

        //这样设置回调可能会导致同一个item下会存在多个匿名函数的点击响应函数,会触发多次回调函数
    itemButton.onClick(this,(item:fairygui.GButton,event:any)=>{
        
    },[itemButton]);

    private onClickItem(item:fairygui.GButton,event:any){
        const itemButton = item.asButton;
        console.log('点击了' + itemButton.title + 'Button');
    }

注:

  • 虚拟列表一旦开启就不能关闭。
  • 设置列表或者虚拟列表的numItems之前需要先设置渲染函数
  • 虚拟列表一定需要设置渲染函数
  • 虚拟列表的溢出处理需要设置成滚动,否则不能开启虚拟列表
    GList_6.png
  • 虚拟列表只能渲染设置好的item组件,可以在编辑器中设置,也可以通过GList.defaultItem设置。
  • 虚拟列表不可以自己管理item,即不可以调用AddChild或者RemoveChild。只能通过numItems改变item的数量
  • 如果想让虚拟列表的首尾相连可以使用GList.setVirtualAndLoop开启
  • 如果需要动态修改item的大小,可以在渲染函数中设置item的大小或者在设置item大小后调用GList.RefreshVirtualList刷新虚拟列表。
  • 获取距离最近的锚点的item的锚点的坐标
console.log(testList.getSnappingPosition(Laya.stage.mouseX,Laya.stage.mouseY));
  • 获取当前处于显示区域中的第一个item的索引
console.log(testList.getFirstChildInView());
  • 调整列表的大小到能够显示全部item的尺寸
testList.resizeToFit();
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345