0.1. 开发环境
- 引擎版本:Cocos Creator 2x & 3x
- 编程语言:TypeScript
0.2. 在线演示
- Cocos Creator | ScrollAdapter
-
新增动态尺寸演示场景
0.3. 商店地址
0.4. 资源介绍
- 这个插件是对原有的super-scrollview升级重构,在支持原有功能以外还增加了更多实用功能,重点是更加灵活,理论上可以通过这个插件实现的功能远远高于上一个版本。
0.6. 简单介绍
1. ScrollManager 参数
1.1. ViewManager 参数
1.2. LayoutManager 参数
1.3. PullReleaseManager 参数
1.4. AutoCenterManager 参数
1.5. PageViewManager 参数
1.6. NestedManager 参数
2. 入门 - 布局
-
新建一个脚本 MyAdapter 继承ScrollAdapter
export class MyAdapter extends ScrollAdapter<ITutorialModel> { @property(Node) prefab1: Node = null @property(Node) prefab2: Node = null @property(Node) prefab3: Node = null @property(Node) prefab4: Node = null /** * 根据数据类型返回相应的预制体 * @param data 用户数据 * @returns 预制体 */ getPrefab(data: ITutorialModel): Node | Prefab { switch (data.prefabType) { case 1: return this.prefab1 case 2: return this.prefab2 case 3: return this.prefab3 case 4: return this.prefab4 // ... 更多Prefab } } /** * 子类实现 创建View实例 */ getView(): View<ITutorialModel> { return new MyView(this) } /** * 子类实现 创建Holder实例 */ getHolder(node: Node, code: string): Holder<ITutorialModel> { return new MyHolder(node, code, this) } }
-
首先介绍下上面出现的
ITutorialModel
View
Holder
分别是什么
ITutorialModel
- 用户自定义数据类型
-
Holder
- 每个Holder绑定一个固定的被实例化的预制体
- Holder一旦被创建,预制体类型就确定了,永远不会改变
- 变化的只有数据
-
View
- View可以理解为单行容器
- 每个View管理多个Holder
- 例如,如果当前主轴方向(就是设置的滚动方向)为垂直时,每个View代表一个填满整个可视区域宽度的一行
- 容器里面的每个Holder就是单独的列
- 所谓的布局就是单独布局整个View里面所有Holder的交叉轴方向(和滚动相反的方向)
-
首先定义自定义数据类型
export interface ITutorialModel { name: string //名称 fixed: boolean //是否固定 prefabType: number //预制体类型 wrapBeforeMode: WrapMode //前换行模式 wrapAfterMode: WrapMode //后换行模式 flexible?: number // 弹性倍数 }
-
在 MyAdapter 的 start 方法里创建自定义数据
start() { var models: ITutorialModel[] = [] for循环 { // 数据结构是自定义的,可以自由发挥,这里举例 // 第一行显示两个不同的预制体 var model1: ITutorialModel = { name: "固定的标题"+ i, prefabType: 1, fixed: true, //标记它为固定标题 /** 相对于前一个元素换行,永远置于新一行起始位置 */ wrapBeforeMode: WrapMode.Wrap, /** 允许下一个元素可以排在自己后面 */ wrapAfterMode: WrapMode.Nowrap, flexible: 0, } var model2: ITutorialModel = { name: "内容" +i, prefabType: 2, fixed: false, /** * 相对于前一个元素不换行,排在它后面 * 能否真正排在前一个元素的后面还要看前一个元素的wrapAfterMode设置 */ wrapBeforeMode: WrapMode.Nowrap, /** 要求下一个元素必须换行,无论它的wrapBeforeMode设置的是什么 */ wrapAfterMode: WrapMode.Wrap, flexible: 1 } models.push(model1, model2) // 第二行只显示一个预制体 var model3: ITutorialModel = { name: "独占一行的内容" + i, prefabType: 3, fixed: false, /** 这个元素永远会独占一行 */ wrapBeforeMode: WrapMode.Wrap, wrapAfterMode: WrapMode.Wrap, flexible: 1 } models.push(model3) // 第三行包括之后的所有行都显示统一的内容,并且自动填满 for循环 { models.push({ name: "#"+ j, fixed: false, prefabType: 4, /** 自动换行 */ wrapBeforeMode: WrapMode.Auto, wrapAfterMode: WrapMode.Nowrap, /** 希望每组数据的第一个尺寸大一些 */ flexible: j == 0 ? 2 : 1 }) } } // 数据准备好了 向modelMananger中插入数据 this.modelManager.insert(models) }
-
以上代码看起来很多,这里只是为了演示方便,写死一些数据,如果没有特殊布局需求的话 wrapBeforeMode,wrapAfterMode,fixed ,flexible 都可以不设置,使用默认值即可
-
接下来看下 View 部分
class MyView extends View<ITutorialModel>{ /** * 设置元素布局规则 每一个IViewElement都是一个被实例化的节点 * @param element 元素布局规则 * @param data 用户数据 */ protected setViewElement(element: IViewElement, data: ITutorialModel): void { // 设置换行模式 element.wrapBeforeMode = data.wrapBeforeMode element.wrapAfterMode = data.wrapAfterMode // 由于我们在创建数据的时候指定了一个名为fixed的标志,代表它是一个固定标题 // 所以这里根据数据来设置是否固定 element.fixed = data.fixed // 不要忘了,固定标题一般都显示在最上层,除非你想要其他效果 if (element.fixed) { //将非固定的提升到最上层, // 层级一共有3中 Lowest Medium Highest,默认所有节点都在 Lowest element.layer = Layer.Highest //设置到最上层 // element.fixedOffset = 30 //固定标题和可视区域顶部的距离 // element.fixedSpacing = 0 //当前标题和下一个固定标题的间距 } /** 第一个元素的值在创建时设置为 2 */ element.flexibleSize.width = data.flexible } protected onVisible(): void { } protected onDisable(): void { } }
-
接下来看下 Holder 部分
class MyHolder extends Holder<ITutorialModel>{ private _label: Label = null /** * 当被创建时,只会执行一次,可以在这里初始化 */ protected onCreated(): void { this._label = this.node.getComponentInChildren(Label) } /** * 每次数据发生变化或从不可见到可见时,不只是用户数据变化,可能当前Holder所属的View变化也会执行 */ protected onVisible(): void { this._label.string = this.data.name } /** * 当被回收为不可见状态时 */ protected onDisable(): void { } }
-
运行结果
-
除了这些以外,布局还有其他属性,一下是完整的属性字段
export interface IViewElement { /** * 前换行,当前元素相对于前一个元素的换行模式,默认值 Wrap */ wrapBeforeMode: WrapMode /** * 后换行,下一个元素相对于自己的换行模式,默认值 Nowrap */ wrapAfterMode: WrapMode /** * 忽略布局,使其不受Layout控制 */ ignoreLayout: boolean /** * 最小尺寸,如果同时设置了preferredSize则取最大值(只会影响滑动反方向) */ minSize: ISizeLike /** * 首选尺寸,如果同时设置了minSize则取最大值(只会影响滑动反方向) */ preferredSize: ISizeLike /** * flex,和CSS flex一样的作用(只会影响滑动反方向) */ flexibleSize: ISizeLike /** * 指定当前数据的层级,如果未设置,使用最低层 Lowest */ layer: Layer /** * 固定到顶部 */ fixed: boolean /** * 开启fixed时有效,固定时顶部的偏移量 */ fixedOffset: number /** * 开启fixed时有效,与下一个设置了fixed的item的间距 */ fixedSpacing: number }
暂时先介绍到这里,内容比较多,日后持续更新教程…
所有演示场景都在3.x中,2.x版本没有演示场景