标签:任务 官方 val 缓冲区 中文 length 上下 数组 ast
ScrollView是比较常用的UI组件之一,游戏中的任务榜、排行榜都少不了它,实际使用中存在一个问题,例如:在排行榜中要显示前100名玩家,如果真的把这100名玩家的信息全部创建,并加载进ScrollView,对移动设备的宝贵内存会是巨大的浪费。其实玩家在屏幕上总能看到的最多只有7、8项而已,所以实际上只用创建比显示多一点的数量,再通过缓冲区实时动态更新机制,就可以给玩家呈现出尽可能多数量的列表(依内存而定,理论上无限),即节省内存,也不影响性能。
在CocosCreate官方提供的example中,有个ScrollView的例子,就使用了动态更新机制,我把它摘出来做为一个单独的工程,加上中文注释,并对代码稍做改动,运行截图如下所示:
可以看到,列表中显示一共有100行,但一屏最多展示7.5行,而实际上在内存中只真正创建了15项,所有看到的这100行,都是在上下滚动事件中,通过动态更新这15项的坐标和内容来实现的。要了解它的运行原理,先看下图:
如图把ScrollView分成三部分,按区域从小到大依次是:
1、屏幕可见区。指屏幕上玩家可看可操作的列表区域,在此demo中有7.5行;
2、缓冲区。指内存中真正创建了的列表所占的区域,在此demo中有15行;
3、content区。指整个ScrollView要显示的区域,在此demo中有100行;
下面再分三种情况讲解:
1、刚初始化完成时:此时在右侧按钮上提示有100行,实际上只创建了第1-15行,而玩家能看到的是第1-7行。如果玩家想要看到更多,必然会向上或向下滚动屏幕;
2、向上滚动时:在移动设备上,如果玩家想要看到下面的行,所做的操作是触摸往上滑动,则整个content区往上移动,也带动content区的item往上移动,update函数会不断遍历所创建的15项item,如果检测到某item的y坐标超出了缓冲区的上边界,则把该item往下移动一个缓冲区的高度,并更新它的显示ID;
3、向下滚动时:同理,content区的item往下移动,update不断遍历所创建的15项item,如果检测到某item的y坐标越过了缓冲区的下边界,则把该item往上移动一个缓冲区的高度,并更新它的显示ID;
关键代码如下所示:
// 返回item在ScrollView空间的坐标值 getPositionInView: function (item) { let worldPos = item.parent.convertToWorldSpaceAR(item.position); let viewPos = this.scrollView.node.convertToNodeSpaceAR(worldPos); return viewPos; }, // 每帧调用一次。根据滚动位置动态更新item的坐标和显示(所以spawnCount可以比totalCount少很多) update: function(dt) { this.updateTimer += dt; if (this.updateTimer < this.updateInterval) { return; // we don‘t need to do the math every frame } this.updateTimer = 0; let items = this.items; // 如果当前content的y坐标小于上次记录值,则代表往下滚动,否则往上。 let isDown = this.scrollView.content.y < this.lastContentPosY; // 实际创建项占了多高(即它们的高度累加) let offset = (this.itemTemplate.height + this.spacing) * items.length; let newY = 0; // 遍历数组,更新item的位置和显示 for (let i = 0; i < items.length; ++i) { let viewPos = this.getPositionInView(items[i]); if (isDown) { // 提前计算出该item的新的y坐标 newY = items[i].y + offset; // 如果往下滚动时item已经超出缓冲矩形,且newY未超出content上边界, // 则更新item的坐标(即上移了一个offset的位置),同时更新item的显示内容 if (viewPos.y < -this.bufferZone && newY < 0) { items[i].setPositionY(newY); let item = items[i].getComponent(‘Item‘); let itemId = item.itemID - items.length; // update item id item.updateItem(i, itemId); } } else { // 提前计算出该item的新的y坐标 newY = items[i].y - offset; // 如果往上滚动时item已经超出缓冲矩形,且newY未超出content下边界, // 则更新item的坐标(即下移了一个offset的位置),同时更新item的显示内容 if (viewPos.y > this.bufferZone && newY > -this.content.height) { items[i].setPositionY(newY); let item = items[i].getComponent(‘Item‘); let itemId = item.itemID + items.length; item.updateItem(i, itemId); } } } // 更新lastContentPosY和总项数显示 this.lastContentPosY = this.scrollView.content.y; this.lblTotalItems.string = "Total Items: " + this.totalCount; },
在此demo中,ScrollView列表显示的item其实是个按钮,而它做为预制资源,其实可以在Creator中编辑成各种UI,并不局限于按钮形式。
最后,附上该Creator工程完整源代码的github地址:https://github.com/foupwang/CocosCreatorScrollViewDemo.git
标签:任务 官方 val 缓冲区 中文 length 上下 数组 ast
原文地址:http://www.cnblogs.com/foupwang/p/7779417.html