cocos论坛原文地址:Cocos Creator ScrollView 性能优化之 UISuperScrollView 开箱即用
代码下载地址:https://github.com/icipiqkm/UISuperScrollView
水友的循环列表
cocos也不提供这样的组件,自己写的列表没有下拉刷新和上拉加载功能,所以如果有项目要用到,直接用水友的好了。
水友的列表是继承cc.ScrollView扩展的,用法就是先创建一个cocos默认的scrollView,把scrollView节点上的cc.ScrollView删除,替换为UISuperScrollView。
在节点content挂上UISuperLayout,这是用于布局。具体使用得看github上demo。
一个普通垂直列表
按着demo自己实现一个普通垂直列表,注意到几个问题:
1 item创建倍率问题
如下图,在item创建倍率默认2情况下,能看见的item是8个,但是创建的item是15个,有很多item都是浪费的。
所以设置item倍率为1.2,这样会减少创建多余的item。例如下图,下拉列表效果不变的情况下,ListItem只有10个。
2 RefreshItemEvents 刷新事件问题
默认刷新事件是在属性面板中设置的
我习惯在代码里监听,所以将RefreshItemEvents属性去掉了,改为代码里监听
UISupserLayout.ts:
一个普通垂直列表的代码Vertical.ts:
/** * 垂直列表 */ @ccclass export default class Vertical extends cc.Component { @property({ type: UISpuerScrollView, tooltip: "列表scrollView" }) scrollView: UISpuerScrollView = null; @property({ type: UISuperLayout, tooltip: "列表layout" }) layout: UISuperLayout = null; private testList = [ { id: 0, msg: "1" }, { id: 1, msg: "1" }, { id: 2, msg: "1" }, { id: 3, msg: "1" }, { id: 4, msg: "1" }, { id: 5, msg: "1" }, { id: 6, msg: "1" }, { id: 7, msg: "1" }, { id: 8, msg: "1" }, { id: 9, msg: "1" }, { id: 10, msg: "1" }, { id: 11, msg: "1" }, { id: 12, msg: "1" }, { id: 13, msg: "1" }, { id: 14, msg: "1" }, { id: 15, msg: "1" }, ] onLoad() { this.layout.node.on(UISuperLayout.REFRESH_ITEM, this.refreshItem, this); this.layout.total(this.testList.length); } /**数据更新 */ private refreshItem(node: cc.Node, index: number) { node.getComponent(ListItem).dataChanged(this.testList[index]); } }
一个普通的水平列表
只要选择UISuperScrollView和UISuperLayout的Horizontal就行了。
一个普通的网格列表
网格列表不需要像cc.ScrollView那样选择Grid布局,而是设置UISuperLayout的每组item个数。
例如上图的网格布局,每列3个item。
一个普通的向上循环
向上或向下循环,勾选UISuperLayout的头部滑动循环和尾部滑动循环就行。
但是这个循环功能是有问题的,如上图列表最长是29,向上显示到0以后,理论上是从29接着循环,实际是从10开始接着循环。
上拉和下拉事件
UI显示方面,在view节点下放上head和foot两个文本,用于显示刷新状态。
head和foot节点的高度必须和UISuperScrollView的顶部偏移量和底部偏移量一致。例如下图中设置为50,那么head和foot节点也必须是50,代码中根据这个值来控制刷新时content的位置。
触发下拉事件的条件是滚动容器滑动距离超过:顶部偏移量*满足触发Header的倍数,如下图就是50*2=100,下拉滑动超过100像素就会触发下拉事件。
水友使用属性面板中来绑定事件的,我改成了在代码中绑定。
我修改了源码,让上拉和下拉事件在代码中监听:
this.scrollView.node.on(UISpuerScrollView.PULL_DOWN, this.pullDown, this); this.scrollView.node.on(UISpuerScrollView.PULL_UP, this.pullUp, this); //下拉事件 private pullDown(event: UISuperHeaderAndFooterEvent){ } //上拉事件 private pullUp(event: UISuperHeaderAndFooterEvent){ }
触发上拉或下拉事件后,需要加载数据并刷新列表,并显示加载和刷新的进度,这些操作需要根据event的值来进行,event意义如下:
完整代码:
import UISuperLayout from "../../src/UISuperLayout"; import UISpuerScrollView, { UISuperHeaderAndFooterEvent } from "../../src/UISuperScrollView"; import ListItem from "../common/ListItem"; const { ccclass, property } = cc._decorator; @ccclass export default class Refresh extends cc.Component { @property({ type: UISpuerScrollView, tooltip: "列表scrollView" }) scrollView: UISpuerScrollView = null; @property({ type: UISuperLayout, tooltip: "列表layout" }) layout: UISuperLayout = null; @property({ type: cc.Node, tooltip: "头部文字根节点" }) head: cc.Node = null; @property({ type: cc.Node, tooltip: "底部文字根节点" }) foot: cc.Node = null; @property({ type: cc.Label, tooltip: "头部文字" }) headLab: cc.Label = null; @property({ type: cc.Label, tooltip: "底部文字" }) footLab: cc.Label = null; private testList = []; onLoad() { for (let i = 0; i < 2; i++) { this.testList.push({ id: i, msg: i + "" }); } this.head.scaleY = 0; this.foot.scaleY = 0; this.layout.node.on(UISuperLayout.REFRESH_ITEM, this.refreshItem, this); this.scrollView.node.on(UISpuerScrollView.PULL_DOWN, this.pullDown, this); this.scrollView.node.on(UISpuerScrollView.PULL_UP, this.pullUp, this); this.layout.total(this.testList.length); } /**数据更新 */ private refreshItem(node: cc.Node, index: number) { node.getComponent(ListItem).dataChanged(this.testList[index]); } /**下拉事件 */ private pullDown(event: UISuperHeaderAndFooterEvent) { //文字显示 if (event.progressStage == "wait") { this.headLab.string = "下拉刷新"; this.head.scaleY = 1; } else if (event.progressStage == "lock") { this.headLab.string = "刷新中"; } //执行刷新操作 if (event.action == true) { for (let i = 0; i < 2; i++) { this.testList.unshift({ id: i, msg: "新增:" + i }); } this.layout.total(this.testList.length); } //隐藏文字显示 if (event.action == false && event.progressStage == "release" && event.progress <= 1) { this.head.scaleY = 0; } } /**上拉事件 */ private pullUp(event: UISuperHeaderAndFooterEvent) { //文字显示 if (event.progressStage == "wait") { this.footLab.string = "上拉刷新"; this.foot.scaleY = 1; } else if (event.progressStage == "lock") { this.footLab.string = "刷新中"; } //执行刷新操作 if (event.action == true) { for (let i = 0; i < 2; i++) { this.testList.push({ id: i, msg: "新增:" + i }); } this.layout.total(this.testList.length); } //隐藏文字显示 if (event.action == false && event.progressStage == "release" && event.progress <= 1) { this.foot.scaleY = 0; } } }