性感码农,在线解答:有什么问题可以扫屏幕右方二维码加我微信或者在下方留言。

ScrollView通常用来显示一些列表内容。例如任务列表,挑战列表,道具列表等等。当显示项目较多时,ScrollView的打开和滑动都会有卡顿。之前我的优化思路是这样的:列表滑动到哪里就创建并显示到哪里,未显示的部分通通移除。有一定的优化效果,但是会产生更多的创建和销毁过程。将其进一步优化,不再销毁和创建新的列表项,而是重复使用。

这篇博客的意图在于提供思路,方法,而不是封装好一个现成的组件给你拿来直接用,这样在遇到类似的列表卡顿问题时基本全都能解决。

简述一下优化思路

滑动列表只创建有限个item,能够充满列表就足够。当ScrollView向上滑动时,检测最上面的一个item位置是否已经滑出列表临界值,如果滑出,则把它移动到当前列表最下面,并更新item上的信息。ScrollView向下滑动时同理。当滑动到上下边缘时做一些特殊处理。

如果是和服务器有通信的列表,例如显示1000个item的排行榜,则可以分批请求数据。和服务器协议好,每次请求100条数据。ScrollView在每次滑动到列表底部的时候去请求新的数据,滑动到底部Creator有自带的方法监听,点击查看ScrollViewAPI文档

点击连接获取Demo

Demo是基于CocosCreator1.9.3版本,重在理解优化原理,任何游戏遇到列表卡顿问题都可以使用这个思路来解决。

Demo中,使用的item结构非常简单,图片也只有一张,所以相比我们游戏中的实际情况要好很多,我们使用1000条模拟数据来对比。

优化效果

通过实际测试,可以看到,未优化过的列表创建时卡顿感觉明显,优化过的列表秒开。

代码中主要的实现逻辑如下:

  1. 在update实时获取一下最上和最下item的位置;
  2. 将上一步骤中获取到的两个位置和上下临界位置做比较;
  3. 如果上item超过临界值,则上item移动到列表尾部,并更新信息;
  4. 如果下item超过临界值,则下item移动到列表首部,并更新信息;
  5. 当到达列表边缘时,不做任何处理。

下面对主要代码做下简要分析,在看分析前,一定要现看Demo,并运行起来

以下是几个比较重要的参数值,可以自行设置

this.itemHeight = 120;//设置每个item的高
this.topIndex = 0;//最上面的item索引id
this.bottomIndex = 7;//最下面的item索引id
this.offsetY = 80;//上下临界坐标补充,点击查看原理,值太小会出现item在边界闪动的情况,因为item可能此时在上下两边时均符合移动的情况,所以就会无限循环移动,此值建议自行调整

//如果觉得这种获取临界坐标的方式比较麻烦,可以多创建几个item,指定屏幕的上下边为边界
let scrollViewPos = this.scrollView.position;//scrollView以屏幕中心为原点的坐标,请自行计算出来
this.topExtremeDistance = scrollViewPos.y + this.scrollView.height / 2 + this.offsetY;//获取item能到达的屏幕上边界y坐标
this.bottomExtremeDistance = scrollViewPos.y - this.scrollView.height / 2 - this.offsetY;//获取item能到达的屏幕下边界y坐标

以下是实现item上下移动的主代码

updateItemsPos (dt) {
    if (!!this.itemsArr && !!this.itemsArr[this.bottomIndex]) {
        //获取上下item当前的坐标
        let topPos = cc.pSub(this.itemsArr[this.topIndex].convertToWorldSpaceAR(cc.v2(0, 0)), cc.v2(cc.winSize.width / 2, cc.winSize.height / 2));
        let bottomPos = cc.pSub(this.itemsArr[this.bottomIndex].convertToWorldSpaceAR(cc.v2(0, 0)), cc.v2(cc.winSize.width / 2, cc.winSize.height / 2));

        //检测上item是否超过边界
        if (topPos.y > this.topExtremeDistance) {
            if (this.bottomIndex >= this.data.length - 1) {
                return;
            }
            this.updateItem(this.itemsArr[this.topIndex], this.data[this.bottomIndex + 1], this.bottomIndex + 1);
            this.topIndex ++;
            this.bottomIndex ++;
        //检测下item是否超过边界
        } else if (bottomPos.y < this.bottomExtremeDistance) {
            if (this.topIndex < 1) {
                return;
            }
            this.updateItem(this.itemsArr[this.bottomIndex], this.data[this.topIndex - 1], this.topIndex - 1);
            this.topIndex --;
            this.bottomIndex --;
        }
    }
},

有问题的童鞋可以在下方留言。

性感码农,在线解答!

发表评论

电子邮件地址不会被公开。 必填项已用*标注