UE4-ListView
UE4ListView和U3D的思路不太一样,详细了解之后发现UE4的ListView还是蛮先进的,直接就实现了逻辑和显示分离,提高效率,相对的,他的用法也比Unity的ListView绕一些。举例,一个ListView如果设置12个Entry,那么它最多同时可以显示12个UI条目,假如你有30个数据,这30个数据是逻辑部分,不会为你创建30个Entry,那样太浪费了,而是循环利用这12个Entry显示,十分环保。当然30个数据似乎差异不大,那么当你有1000条数据的时候,优势就十分明显了。
这里要注意几个概念。
ListView,可以视为容器。
Entry,可以视为ListViewItem的显示部分,他负责实时的和逻辑绑定。Entry本身是一个Widget,要继承UseObjectListEntry接口。
逻辑部分,自己建立一个继承自Object的数据载体就好,它通常是【数据源】的集合。
1-首先构建ListView的Entry
新建UI蓝图,取名字为ListEntryItem
设计Entry。切换到Graph,打开ClassSettings,添加UseObjectListEntry接口。
2-构建ListView
新建UI蓝图,取名字ListUI
设置UpgradeList的Entry,为刚才我们创建的ListEntryItem
3-创建数据载体
Object蓝图,添加3个字段
ItemContent Text类型
IsSelect Bool型
CachedIndex Int型,这个纯是为了Debug方便加的,没有也行。
4-事件触发顺序
先讲一下事件触发顺序,和特殊规则。否则以后遇到坑的时候都不知道自己为什么被坑。
打开页面时触发:
ListUI的事件
首先触发的是LsitUI的EventConstruct。当成构造函数就好。
ListEntryItem的事件
当你向ListUI填数据的时候,ListView会判断这个数据是否需要显示,如果需要显示,就会创建Entry(或回收再利用Entry)并触发这个事件。
当你选择其他的物件时
先调用失去焦点的ListEntryItem物件的
ListEntryItem的事件
再调用获得焦点的ListEntryItem物件的
最后调用容器,也就是ListView的
ListUI的事件
然后还需要注意的是
当你拖动ListView,使得Entry代表的数据Object发生变化时,也会调用
ListEntryItem的
事件,这很好理解,当Entry循环利用的时候,Entry肯定会切换数据Object,那么想要显示新的数据内容,肯定也要触发一次数据绑定事件。
4 三个坑
这三个坑其实是源于ListView自身的机制。但是理解其原理之后,就能绕过这些坑。
为什么要先讲这个呢,这时因为使用ListView有3个坑。
第一个坑:数据和状态都不能存到Entry上,Entry应该只负责显示,最多持有一个当前数据Object的一个引用。否则,一个100个Item和10个Entry的ListView,每个Entry要被10个Item用,如果你把状态,比如选中状态存再Entry上面,那么当你改变一个Entry状态的时候,10个数据Item都会发生异变。比如你选择1号Entry,那么11,21,31...都会发生相同的变化。
第二个坑:我们打个比方,比如一个数据Object正在被一个Entry显示,我们说他为【上班】状态,否则,说他是【下班】状态。一个Entry,滑动ListView将其划走,这时候Entry的对应的数据Object,就会下班。而如果这个数据Object下班了,也就说明他不再和Entry关联,那么你理所当然的,不能指望依靠Entry里面的
事件去改变这个处于下班状态的数据Object的IsSelect状态。所以,你需要编辑ListView的
事件,并缓存一个【上一个选择的数据Item】的引用。
第三个坑:第一次选择不同的Entry的时候,不会为当前的Entry调用Select事件。只有第二次点击Entry的时候,才会调用上一个Entry的EventOnItemSelectionChanged,并再其后调用新选择目标的EventOnItemSelectionChanged。这样有些时候,第一个Entry如果被设为默认选中状态,他就没法被正常取消了。
5-使用ListView的一种思路
1 构造ListView
功能简单明了
循环30次,将所有数据添加给ListView。用字符串+索引作为其显示数据。同时将索引存入CacchedIndex
2 设置Entry数据的函数,这里只设置text。因为索引是不变的。
3 为ListEntryItem添加 UpdateView函数
用来更新ListView显示状态
4 选择焦点变化处理
当选择发生变化时为新被选择的物件,添加事件设置其选择状态。如果一个数据恰好也被Entry绑定并显示出来,同时触发取消选择状态的Entry的这个事件,将其改成不显示状态。
5 后台变更数据Object选中状态
如果一个数据Object没被显示出来,Entry的事件是处理不了它的,那么这时候就要ListView亲自出马了。
判断当前缓存的物件,是不是和当前选中物件一致,如果是,先把当前缓存物件的isSelect设False,然后将其作为新的缓存物件保存起来。
最终效果:
只能选中一个物件,并且上下滑的时候状态不会错乱。
PS:如果实在整不明白,那就让Entry的数量==数据对象的数量吧,那样是没有坑的,因为一个Entry和一个数绑定并且不会切换,但是效率问题就自己想办法吧。