1.做了什么
问题:
在使用ListView的时候,有多少个数据就会创建多少个item,并不会重复利用或回收释放。
随着数据量的增加,会对性能造成很大的影响。
解决方案:
clone 改成 create[据说是这样,我没有测试过 = =…]
我们在使用ListView的时候,创建一个item,是通过lua重写的pushBackCustomItemView,
它会先调用ListView的pushBackDefaultItem,通过clone创建一个csb,我们再把数据赋过去。
所以,我们完全可以create一个csb,相对于clone会快一些。缺点: 这个应该会有点效果,嗯,有点效果而已。
分帧加载(逐帧加载)
并不是在一帧全加载完,而是选择每帧加载一定个数,直到加载完成缺点: 通过lua现有的协程来实现,但是流畅度不是很好,刚进入界面的时候可能看到item是逐渐加载进来的。
异步加载
这个主要对一些图片多的item,我们如果需要切换图,可以通过异步加载,等图片加载完再换图,这样不影响之后item的加载。缺点: 会看到 默认图(csb创建的样子) -> 真正效果的转换过程。
滑动到底加载
就是先加载一定数量,监听到底部了,再拉取后面的部分,直到全部加载完。缺点: 做一系列监听滑动等,没有根本解决问题。
重用item[本次实现的方法]
其实,上面的那些方法,都是优化的技巧,并没有从根本上解决问题。
我们要根本的解决问题,就是创建可视区域可容纳数量+1的item,然后不断重用这些item。
在ListView同一时刻,只能见到5个item,那我就创建6个item,然后不断重用这些item。
2.怎么做的
机制
首先明确view与inner,
view像一个窗口,它的大小就是我们可以见到的大小(当然要设置裁切),
inner是我们创建的所有item添加的地方(item并不是加载ScrollView上,而是加在了inner上)
ScrollView/ListView会监听滑动,同时相应的移动inner的位置,从而让我们看到item位置的变化。
简而言之,item加载inner上,是inner动,不是view动。
想法
在ScrollView或者ListView中,正常情况是这样的:
(前面数字代表item位置,后面数字代表item, ~~~~代表可视区域)
1 1 1
~~~~
2 2 2
3 3 3
~~~~
4 4 4
~~~~
5 5 5
6 6 6
~~~~
7 7 7
8 8 8
可以发现,
前面的例子中, 只能看见2, 3, 4; 但是看不见的1, 5, 6, 7, 8 依旧存在
后面的例子中, 只能看见4, 5, 6; 但是看不见的1, 2, 3, 7, 8 依旧存在
所以,我们改成下面的样子:
1
~~~~
2 2
3 3
~~~~
4 4 4
~~~~
5 5
6 6
~~~~
7
8
因为可视区域只有3个item,我们就创建3个item,然后不断重用它们。(当然实际操作中,需要多创建一个,否则有穿帮风险)
但是,位置,我们依旧留着(划重点,* inner大小不变 *,否则无法滑动),
在往下滑的时候,最上面的跑到下面去顶替下面的item;
往上滑的时候,最下面的跑到上面去顶替上面的item;
做法
实现方法,
可以通过监听ScrollView滑动,每当ScrollView滚动,我们可以知道当前inner位置,
然后知道item的位置,从而判断item需不需要移动位置。
这里,用的是编辑一个绘制方法,每隔一段时间,都看一下各个item位置,然后根据需求移动位置。
我们在加载csb的时候将ScrollView记录下来,在view的update中调用它。
(本来想重写update,但是遇到了一些问题,所以妥协用了它,具体可以看后面 遇到的问题)
init:
--[[
name : item类名
totalItemNum : item总数
... : 创建item时需要的参数
--]]
function ScrollView:setItemViewModel(name, totalItemNum, ...)
主要代码:
-- 得到所需绘制item个数
local count = math.ceil(self:getContentSize().height / self.tItemContentSize.height) + 1
for i = 1, count do
-- 创建item
local view = CSBReaderLoad(name)
view:init(...)
if view.setIndex then
view:setIndex(i)
end