@cc-component/cc-ex-component 1.2.7 → 1.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/core/BaseReference.ts +10 -1
- package/assets/core/ReferenceComponent.ts +36 -23
- package/assets/core/ViewModel.ts +209 -166
- package/assets/lib/collectView/lib_collect/yx-collection-view.ts +14 -0
- package/assets/lib/collectView/lib_collect/yx-flow-layout.ts +12 -5
- package/assets/lib/collectView/lib_collect/yx-page-layout.ts +100 -0
- package/assets/lib/collectView/lib_collect/yx-page-layout.ts.meta +9 -0
- package/assets/lib/tableView/ListView.ts +1 -1
- package/assets/lib/tableView/ListViewPage.ts +56 -20
- package/assets/lib/tableView/ListViewPageLoop.ts +1 -1
- package/assets/lib/tableView/TableView.ts +22 -2
- package/package.json +1 -1
|
@@ -18,8 +18,12 @@ export class BaseReference extends Component {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
onLoadFinish() {
|
|
21
|
-
if (this.vmParams)
|
|
21
|
+
if (this.vmParams) {
|
|
22
|
+
this.viewModel?.refreshUI(this.vmParams)
|
|
23
|
+
// this.vmParams = null
|
|
24
|
+
}
|
|
22
25
|
}
|
|
26
|
+
|
|
23
27
|
//#endregion
|
|
24
28
|
defineProperty(propertyKey: string) {
|
|
25
29
|
Object.defineProperty(this, propertyKey, { get: () => this.rc?.get(propertyKey), set: (value) => { }, configurable: true });
|
|
@@ -28,6 +32,11 @@ export class BaseReference extends Component {
|
|
|
28
32
|
|
|
29
33
|
refreshUI(vmParams: any) {
|
|
30
34
|
this.vmParams = vmParams;
|
|
35
|
+
if (this.vmParams) {
|
|
36
|
+
this.viewModel?.refreshUI(this.vmParams)
|
|
37
|
+
/// this.vmParams = null
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
}
|
|
32
41
|
protected onDestroy(): void {
|
|
33
42
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Sprite } from "cc";
|
|
2
|
+
import { assetManager } from "cc";
|
|
3
|
+
import { Button } from "cc";
|
|
2
4
|
import { Enum } from "cc";
|
|
3
5
|
import { _decorator, Component, js, Node } from "cc";
|
|
4
6
|
import { EDITOR_NOT_IN_PREVIEW } from "cc/env";
|
|
@@ -25,6 +27,7 @@ export class ReferenceComponent extends Component {
|
|
|
25
27
|
@property({ displayName: "复制属性" })
|
|
26
28
|
private get refresh() { return this._refresh; }
|
|
27
29
|
private set refresh(val: boolean) {
|
|
30
|
+
console.error('打印了')
|
|
28
31
|
if (EDITOR_NOT_IN_PREVIEW) {
|
|
29
32
|
this.initNodeList();
|
|
30
33
|
this.genCode();
|
|
@@ -82,6 +85,7 @@ export class ReferenceComponent extends Component {
|
|
|
82
85
|
comList2 = ["YXCollectionView", "TableView"]
|
|
83
86
|
comList_base = ["EditBox", "Toggle", "ToggleContainer", "Slider", "Button", "ProgressBar"]
|
|
84
87
|
|
|
88
|
+
skipList = ["Button"]//跳过按钮类型
|
|
85
89
|
protected onLoad(): void {
|
|
86
90
|
if (EDITOR_NOT_IN_PREVIEW) {//处理编辑器逻辑
|
|
87
91
|
this.initNodeList();
|
|
@@ -187,6 +191,7 @@ export class ReferenceComponent extends Component {
|
|
|
187
191
|
text += line;
|
|
188
192
|
});
|
|
189
193
|
Editor.Clipboard.write("text", text);
|
|
194
|
+
|
|
190
195
|
console.log("已复制到剪切板");
|
|
191
196
|
}
|
|
192
197
|
|
|
@@ -194,8 +199,8 @@ export class ReferenceComponent extends Component {
|
|
|
194
199
|
private genCodeBind(isCopy: boolean = true, isClass: boolean = false) {
|
|
195
200
|
if (!EDITOR_NOT_IN_PREVIEW) return;
|
|
196
201
|
let text = "";
|
|
197
|
-
let eventStr: string = " //#region
|
|
198
|
-
let pix = "onClick_"
|
|
202
|
+
let eventStr: string = " //#region ⚠️ ------------方法事件"
|
|
203
|
+
let pix = "private onClick_"
|
|
199
204
|
// const com = this.node.components.find(v => { return v.reference })
|
|
200
205
|
// const match = com.name.match(/<([^>]+)>/);
|
|
201
206
|
// const className = match && match[1] ? match[1] : "any"
|
|
@@ -203,15 +208,15 @@ export class ReferenceComponent extends Component {
|
|
|
203
208
|
let data = `${className}Data`
|
|
204
209
|
let iinterface = `I${className}Data`
|
|
205
210
|
//console.error("[MLogger Error]", className)
|
|
206
|
-
const viewModel =
|
|
211
|
+
const viewModel =
|
|
212
|
+
`\n //#region ⚠️ ------------自动生成属性
|
|
207
213
|
// ✅ 外部界面调用,刷新UI
|
|
208
214
|
public refreshUI(data: ${iinterface}) { super.refreshUI(data); }
|
|
209
215
|
|
|
210
|
-
|
|
211
|
-
@BindViewModel(${className}Data)
|
|
216
|
+
// ✅ 使用新装饰器(自动响应式 + 路径推导)
|
|
212
217
|
viewModel: ${className}Data;`
|
|
213
218
|
text += viewModel + "\n\n"
|
|
214
|
-
text += `
|
|
219
|
+
text += ` // ✅ UI属性`
|
|
215
220
|
//生成get属性
|
|
216
221
|
this.nodes.forEach(data => {
|
|
217
222
|
let key = data.key;
|
|
@@ -249,10 +254,12 @@ export class ReferenceComponent extends Component {
|
|
|
249
254
|
bind_pix = `@BindTable`
|
|
250
255
|
}
|
|
251
256
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
257
|
+
|
|
258
|
+
let bind = `${bind_pix}("${name}"${this.comList2.includes(type) ? event : ""})`
|
|
259
|
+
if (this.skipList.includes(type)) {
|
|
260
|
+
bind = `${bind_pix}()`
|
|
255
261
|
}
|
|
262
|
+
|
|
256
263
|
if (this.comList_base.includes(type)) {
|
|
257
264
|
|
|
258
265
|
eventStr += `
|
|
@@ -265,12 +272,16 @@ export class ReferenceComponent extends Component {
|
|
|
265
272
|
let line = ` ${bind} @Ref ${name}: ${type};`
|
|
266
273
|
text += line;
|
|
267
274
|
});
|
|
275
|
+
text += `\n //#endregion END`
|
|
268
276
|
|
|
277
|
+
text += `\n\n //#region ⚠️ ------------自定义属性`
|
|
278
|
+
text += `\n\n //#endregion END`
|
|
269
279
|
|
|
270
280
|
if (isCopy) {
|
|
271
281
|
Editor.Clipboard.write("text", text);
|
|
272
282
|
console.log("已复制到剪切板");
|
|
273
283
|
}
|
|
284
|
+
eventStr += `\n //#endregion END`
|
|
274
285
|
return { text: text, event: eventStr }
|
|
275
286
|
|
|
276
287
|
}
|
|
@@ -280,33 +291,35 @@ export class ReferenceComponent extends Component {
|
|
|
280
291
|
if (!EDITOR_NOT_IN_PREVIEW) return;
|
|
281
292
|
let text = ""
|
|
282
293
|
let sx_this = ''
|
|
283
|
-
let sx = '
|
|
294
|
+
let sx = ''
|
|
284
295
|
const className = this.node.name
|
|
285
296
|
|
|
286
297
|
let data = `${className}Data`
|
|
287
298
|
let iinterface = `I${className}Data`
|
|
288
299
|
|
|
289
300
|
//生成get属性
|
|
290
|
-
this.nodes.forEach(data => {
|
|
301
|
+
this.nodes.forEach((data, index) => {
|
|
291
302
|
let key = data.key;
|
|
292
303
|
let name = key[0].toLowerCase() + key.substring(1);
|
|
293
304
|
const type = this.getPropertyType(data.com)
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
305
|
+
if (!this.skipList.includes(type)) {
|
|
306
|
+
//@ts-ignore
|
|
307
|
+
let line = ` ${name}: ${this.getDataTypeByComponentType(type)};`//`private get ${name}() { return this.rc.get("${key}", ${this.getPropertyType(data.node)}); }`;
|
|
308
|
+
sx += line + "" + (index < this.nodes.length - 1 ? "\n" : "");
|
|
297
309
|
|
|
298
|
-
|
|
299
|
-
|
|
310
|
+
let line_sx = ` this.${name} = ${this.getDataTypeByComponentTypeValue(type)}`
|
|
311
|
+
sx_this += line_sx + (index < this.nodes.length - 1 ? "\n" : "");
|
|
312
|
+
}
|
|
300
313
|
});
|
|
301
314
|
|
|
302
315
|
text = `
|
|
303
|
-
//#region
|
|
316
|
+
//#region ⚠️ ------------数据接口
|
|
304
317
|
export interface ${iinterface} {
|
|
305
318
|
${sx}
|
|
306
319
|
}
|
|
307
|
-
|
|
320
|
+
//#endregion END`;
|
|
308
321
|
text += `
|
|
309
|
-
//#region
|
|
322
|
+
//#region ⚠️ ------------数据对象
|
|
310
323
|
class ${data} extends BaseViewModelData implements ${iinterface} {
|
|
311
324
|
${sx}
|
|
312
325
|
|
|
@@ -315,7 +328,7 @@ ${sx}
|
|
|
315
328
|
${sx_this}
|
|
316
329
|
}
|
|
317
330
|
}
|
|
318
|
-
|
|
331
|
+
//#endregion END`;
|
|
319
332
|
if (isCopy) {
|
|
320
333
|
Editor.Clipboard.write("text", text);
|
|
321
334
|
console.log("已复制到剪切板");
|
|
@@ -331,7 +344,7 @@ ${sx_this}
|
|
|
331
344
|
private genCodeVmDataAll() {
|
|
332
345
|
if (!EDITOR_NOT_IN_PREVIEW) return;
|
|
333
346
|
let importStr = `
|
|
334
|
-
import { Label, RichText, ProgressBar, Sprite, EditBox, Toggle, Slider, ToggleContainer, Button, math, SpriteFrame, _decorator } from 'cc';
|
|
347
|
+
import { Label, RichText, ProgressBar, Sprite, EditBox, Toggle, Slider, ToggleContainer, Button, math, SpriteFrame, _decorator , Node} from 'cc';
|
|
335
348
|
import { ViewModel, BindViewModel, BindTable, BindCollect, Bind, Ref, BaseViewModelData, YXCollectionView, YXFlowLayout, TableView, BaseReference } from 'db://assets/pkg-export/@cc-component/cc-ex-component';
|
|
336
349
|
const { ccclass, property } = _decorator;`
|
|
337
350
|
|
|
@@ -354,7 +367,7 @@ const { ccclass, property } = _decorator;
|
|
|
354
367
|
|
|
355
368
|
let iinterface = `I${className}Data`
|
|
356
369
|
const onload = `
|
|
357
|
-
//#region
|
|
370
|
+
//#region ⚠️ ------------初始化
|
|
358
371
|
onLoad(): void {
|
|
359
372
|
|
|
360
373
|
}
|
|
@@ -363,6 +376,7 @@ const { ccclass, property } = _decorator;
|
|
|
363
376
|
this.viewModel.loadData()
|
|
364
377
|
}`
|
|
365
378
|
const classView = `
|
|
379
|
+
@BindViewModel(${className}Data)
|
|
366
380
|
@ccclass('${className}')
|
|
367
381
|
export class ${className} extends ViewModel(BaseReference) {${sx.text}\n${onload}\n\n${sx.event}\n}`
|
|
368
382
|
|
|
@@ -446,5 +460,4 @@ export class ${className} extends ViewModel(BaseReference) {${sx.text}\n${onload
|
|
|
446
460
|
};
|
|
447
461
|
return typeMap[compType] ?? 'any'; // 默认 fallback
|
|
448
462
|
}
|
|
449
|
-
|
|
450
463
|
}
|
package/assets/core/ViewModel.ts
CHANGED
|
@@ -15,18 +15,25 @@ import { TableView } from '../lib/tableView/TableView';
|
|
|
15
15
|
import { YXFlowLayout } from '../lib/collectView/lib_collect/yx-flow-layout';
|
|
16
16
|
import { math } from 'cc';
|
|
17
17
|
import { YXCollectionView, YXIndexPath } from '../lib/collectView/lib_collect/yx-collection-view';
|
|
18
|
+
import { EventTouch } from 'cc';
|
|
19
|
+
import { YXPagelayout } from '../lib/collectView/lib_collect/yx-page-layout';
|
|
18
20
|
|
|
19
21
|
interface IBindingData extends ITableViewEvents, IBindingDataEvents {
|
|
20
22
|
dataPath: string;
|
|
21
23
|
type: any;
|
|
24
|
+
propertyKey?: string;
|
|
22
25
|
// 允许任意额外属性
|
|
23
26
|
[key: string]: any;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
interface IBindingDataEvents {
|
|
28
|
-
reset?:
|
|
29
|
-
event?:
|
|
31
|
+
reset?: (self: any, value: any, com: Component) => void;
|
|
32
|
+
event?: (self: any) => void;
|
|
33
|
+
touchStart?: (self: any, event: EventTouch) => void;
|
|
34
|
+
touchMove?: (self: any, event: EventTouch) => void;
|
|
35
|
+
touchEnd?: (self: any, event: EventTouch) => void;
|
|
36
|
+
touchCancel?: (self: any, event: EventTouch) => void;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
|
|
@@ -68,6 +75,50 @@ export const refMap: Map<string, string[]> = new Map();
|
|
|
68
75
|
// "cc.Toggle": Toggle,
|
|
69
76
|
// "cc.Button": Button,
|
|
70
77
|
// }
|
|
78
|
+
export function BindViewModel<T extends new () => any>(constructor: T) {
|
|
79
|
+
return function (target: any) {
|
|
80
|
+
const onLoad = target.prototype.onLoad;
|
|
81
|
+
/**
|
|
82
|
+
* 重载onload 注入更新
|
|
83
|
+
*/
|
|
84
|
+
target.prototype.onLoad = function () {
|
|
85
|
+
onLoad.call(this);
|
|
86
|
+
const className = js.getClassName(target);
|
|
87
|
+
if (!bindingMap.has(className)) {
|
|
88
|
+
bindingMap.set(className, new Map());
|
|
89
|
+
}
|
|
90
|
+
//console.log('onLoad我的', this.node.name)
|
|
91
|
+
if (!this._bindings) this._bindings = [];
|
|
92
|
+
|
|
93
|
+
const map = bindingMap.get(className)
|
|
94
|
+
for (const [propertyKey, value] of map) {
|
|
95
|
+
//属性绑定
|
|
96
|
+
this.initReferenceCollector();
|
|
97
|
+
this.defineProperty(propertyKey);
|
|
98
|
+
|
|
99
|
+
//设置类型
|
|
100
|
+
const com = this[propertyKey];
|
|
101
|
+
const classname = js.getClassName(com)
|
|
102
|
+
value.type = classname
|
|
103
|
+
// console.log('属性绑定', propertyKey, value.type, com, this)
|
|
104
|
+
// 记录绑定关系到实例
|
|
105
|
+
this._bindings.push({ uiProp: value.propertyKey, dataPath: value.dataPath });
|
|
106
|
+
// 初始化 UI
|
|
107
|
+
const value_data = this._getNestedValue(this, value.dataPath);
|
|
108
|
+
const data = map.get(propertyKey)
|
|
109
|
+
updateStatus(data, com, value_data, this);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// 创建实例并转为响应式
|
|
113
|
+
const vm_data = 'viewModel'
|
|
114
|
+
const instance = new constructor();
|
|
115
|
+
this[vm_data] = this._makeReactive(instance, vm_data);
|
|
116
|
+
|
|
117
|
+
this.onLoadFinish();
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
}
|
|
71
122
|
|
|
72
123
|
/**
|
|
73
124
|
* 数据绑定装饰器
|
|
@@ -75,50 +126,35 @@ export const refMap: Map<string, string[]> = new Map();
|
|
|
75
126
|
* @param reset 重写赋值方法,自定义实现. 参数:(self 组件所在的父类,com 组件,value 值)
|
|
76
127
|
* @param event 点击事件,滑动事件,等等. 参数:(self 组件所在的父类)
|
|
77
128
|
*/
|
|
78
|
-
export function Bind<T extends Component>(
|
|
79
|
-
dataPath = baseData + '.' +
|
|
129
|
+
export function Bind<T extends Component>(path?: string, param?: IBindingDataEvents) {
|
|
130
|
+
const dataPath = baseData + '.' + path;
|
|
80
131
|
return function (target: any, propertyKey: string) {
|
|
81
|
-
const className = js.getClassName(target
|
|
82
|
-
if (!bindingMap.has(className)) {
|
|
83
|
-
bindingMap.set(className, new Map());
|
|
84
|
-
}
|
|
132
|
+
const className = js.getClassName(target);
|
|
85
133
|
const data: IBindingData = {
|
|
86
|
-
|
|
134
|
+
propertyKey: propertyKey,
|
|
135
|
+
dataPath: dataPath, type: className, reset: param?.reset, event: param?.event,
|
|
87
136
|
itemSize: null,
|
|
88
137
|
cellForItemAt: null,
|
|
89
138
|
numberOfItems: null,
|
|
139
|
+
touchStart: param?.touchStart,
|
|
140
|
+
touchMove: param?.touchMove,
|
|
141
|
+
touchEnd: param?.touchEnd,
|
|
142
|
+
touchCancel: param?.touchCancel,
|
|
90
143
|
}
|
|
91
144
|
|
|
145
|
+
if (!bindingMap.has(className)) { bindingMap.set(className, new Map()); }
|
|
92
146
|
bindingMap.get(className)!.set(propertyKey, data);
|
|
93
|
-
// 重写 onLoad 以初始化绑定
|
|
94
|
-
const originalOnLoad = target.constructor.prototype.onLoad;
|
|
95
|
-
target.constructor.prototype.onLoad = function () {
|
|
96
|
-
originalOnLoad?.call(this);
|
|
97
|
-
const com = this[propertyKey];
|
|
98
|
-
const classname = js.getClassName(com)
|
|
99
|
-
data.type = classname;
|
|
100
|
-
bindingMap.get(className)!.set(propertyKey, data);
|
|
101
|
-
// 初始化 UI
|
|
102
|
-
const value = this._getNestedValue(this, dataPath);
|
|
103
|
-
if (com) {
|
|
104
|
-
updateStatus(data, com, value, this)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// 记录绑定关系到实例
|
|
108
|
-
if (!this._bindings) this._bindings = [];
|
|
109
|
-
this._bindings.push({ uiProp: propertyKey, dataPath });
|
|
110
|
-
};
|
|
111
147
|
};
|
|
112
148
|
}
|
|
113
149
|
|
|
150
|
+
|
|
114
151
|
export function BindTable<T extends Component>(dataPath: string, param?: ITableViewEvents) {
|
|
115
152
|
dataPath = baseData + '.' + dataPath;
|
|
116
153
|
return function (target: any, propertyKey: string) {
|
|
117
154
|
const className = js.getClassName(target.constructor);
|
|
118
|
-
if (!bindingMap.has(className)) {
|
|
119
|
-
bindingMap.set(className, new Map());
|
|
120
|
-
}
|
|
121
155
|
const data: IBindingData = {
|
|
156
|
+
propertyKey: propertyKey,
|
|
157
|
+
|
|
122
158
|
dataPath: dataPath, type: null,
|
|
123
159
|
itemSize: param.itemSize,
|
|
124
160
|
cellForItemAt: param.cellForItemAt,
|
|
@@ -126,26 +162,8 @@ export function BindTable<T extends Component>(dataPath: string, param?: ITableV
|
|
|
126
162
|
onTouchCellAt: param.onTouchCellAt,
|
|
127
163
|
moveFinish: param.moveFinish,
|
|
128
164
|
}
|
|
129
|
-
|
|
165
|
+
if (!bindingMap.has(className)) { bindingMap.set(className, new Map()); }
|
|
130
166
|
bindingMap.get(className)!.set(propertyKey, data);
|
|
131
|
-
// 重写 onLoad 以初始化绑定
|
|
132
|
-
const originalOnLoad = target.constructor.prototype.onLoad;
|
|
133
|
-
target.constructor.prototype.onLoad = function () {
|
|
134
|
-
originalOnLoad?.call(this);
|
|
135
|
-
const com = this[propertyKey];
|
|
136
|
-
const classname = js.getClassName(com)
|
|
137
|
-
data.type = classname;
|
|
138
|
-
bindingMap.get(className)!.set(propertyKey, data);
|
|
139
|
-
// 初始化 UI
|
|
140
|
-
const value = this._getNestedValue(this, dataPath);
|
|
141
|
-
if (com) {
|
|
142
|
-
updateStatus(data, com, value, this)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// 记录绑定关系到实例
|
|
146
|
-
if (!this._bindings) this._bindings = [];
|
|
147
|
-
this._bindings.push({ uiProp: propertyKey, dataPath });
|
|
148
|
-
};
|
|
149
167
|
};
|
|
150
168
|
}
|
|
151
169
|
|
|
@@ -153,11 +171,9 @@ export function BindCollect<T extends Component>(dataPath: string, param?: IColl
|
|
|
153
171
|
dataPath = baseData + '.' + dataPath;
|
|
154
172
|
return function (target: any, propertyKey: string) {
|
|
155
173
|
const className = js.getClassName(target.constructor);
|
|
156
|
-
if (!bindingMap.has(className)) {
|
|
157
|
-
bindingMap.set(className, new Map());
|
|
158
|
-
}
|
|
159
174
|
|
|
160
175
|
const data: IBindingData = {
|
|
176
|
+
propertyKey: propertyKey,
|
|
161
177
|
dataPath: dataPath, type: null,
|
|
162
178
|
layout: param.layout,
|
|
163
179
|
cellForItemAt: param.cellForItemAt as any,
|
|
@@ -165,31 +181,8 @@ export function BindCollect<T extends Component>(dataPath: string, param?: IColl
|
|
|
165
181
|
itemSize: param.itemSize as any,
|
|
166
182
|
onTouchCellAt: param.onTouchCellAt,
|
|
167
183
|
}
|
|
168
|
-
|
|
169
|
-
// layout: (self: any) => YXFlowLayout,
|
|
170
|
-
// cellForItemAt: (self: any, indexPath: YXIndexPath, collectionView: YXCollectionView) => Node
|
|
171
|
-
// itemSize?: ((self: any, indexPath: YXIndexPath, layout: YXFlowLayout, collectionView: YXCollectionView) => math.Size),
|
|
172
|
-
// onTouchCellAt?: (self: any, indexPath: YXIndexPath) => void
|
|
173
|
-
// numberOfItems?: ((self: any, section: number, collectionView: YXCollectionView) => number);
|
|
184
|
+
if (!bindingMap.has(className)) { bindingMap.set(className, new Map()); }
|
|
174
185
|
bindingMap.get(className)!.set(propertyKey, data);
|
|
175
|
-
// 重写 onLoad 以初始化绑定
|
|
176
|
-
const originalOnLoad = target.constructor.prototype.onLoad;
|
|
177
|
-
target.constructor.prototype.onLoad = function () {
|
|
178
|
-
originalOnLoad?.call(this);
|
|
179
|
-
const com = this[propertyKey];
|
|
180
|
-
const classname = js.getClassName(com)
|
|
181
|
-
data.type = classname;
|
|
182
|
-
bindingMap.get(className)!.set(propertyKey, data);
|
|
183
|
-
// 初始化 UI
|
|
184
|
-
const value = this._getNestedValue(this, dataPath);
|
|
185
|
-
if (com) {
|
|
186
|
-
updateStatus(data, com, value, this)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// 记录绑定关系到实例
|
|
190
|
-
if (!this._bindings) this._bindings = [];
|
|
191
|
-
this._bindings.push({ uiProp: propertyKey, dataPath });
|
|
192
|
-
};
|
|
193
186
|
};
|
|
194
187
|
}
|
|
195
188
|
/**
|
|
@@ -280,19 +273,20 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
280
273
|
|
|
281
274
|
const sx = data.dataPath.split('.').pop();
|
|
282
275
|
const tempData = { value: value, skip: false }
|
|
276
|
+
//console.log("updateStatus", data.propertyKey)
|
|
283
277
|
switch (data.type) {
|
|
284
278
|
case 'cc.Label':
|
|
285
279
|
if (data.reset) {
|
|
286
280
|
data.reset(self, value, com);
|
|
287
281
|
} else {
|
|
288
|
-
if (value) (com as Label).string = value?.toString() || '';
|
|
282
|
+
if (value != undefined && value !== null) (com as Label).string = value?.toString() || '';
|
|
289
283
|
}
|
|
290
284
|
break;
|
|
291
285
|
case 'cc.RichText':
|
|
292
286
|
if (data.reset) {
|
|
293
287
|
data.reset(self, value, com);
|
|
294
288
|
} else
|
|
295
|
-
if (value)
|
|
289
|
+
if (value != undefined && value !== null)
|
|
296
290
|
(com as RichText).string = value?.toString() || '';
|
|
297
291
|
break;
|
|
298
292
|
case 'cc.Sprite':
|
|
@@ -301,7 +295,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
301
295
|
if (data.reset) {
|
|
302
296
|
data.reset(self, value, com);
|
|
303
297
|
} else
|
|
304
|
-
if (value) (com as Sprite).spriteFrame = value;
|
|
298
|
+
if (value != undefined && value !== null) (com as Sprite).spriteFrame = value;
|
|
305
299
|
break;
|
|
306
300
|
case 'cc.Button':
|
|
307
301
|
const com_btn = (com as Button);
|
|
@@ -310,86 +304,147 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
310
304
|
} else
|
|
311
305
|
com_btn.node.active = value ?? true;
|
|
312
306
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
307
|
+
//事件点击
|
|
308
|
+
|
|
309
|
+
const touch_click = 'CallClick'
|
|
310
|
+
if (!com_btn[touch_click]) {
|
|
311
|
+
const sx = data.propertyKey;
|
|
312
|
+
com_btn.node.off(Button.EventType.CLICK, com_btn[touch_click]);
|
|
313
|
+
tempData.skip = true;
|
|
314
|
+
const btnCall = (btn) => {
|
|
315
|
+
tempData.value = btn.node.active
|
|
316
|
+
self.viewModel[sx] = tempData
|
|
317
|
+
data.event?.(self)
|
|
318
|
+
self[`onClick_${sx}`]?.(btn)
|
|
319
|
+
}
|
|
320
|
+
com_btn[touch_click] = btnCall
|
|
321
|
+
com_btn.node.on(Button.EventType.CLICK, btnCall);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
//touch
|
|
325
|
+
let touch_start = 'CALL_TOUCH_START'
|
|
326
|
+
if (data.touchStart && !com_btn[touch_start]) {
|
|
327
|
+
com_btn.node.off(Node.EventType.TOUCH_START, com_btn[touch_start]);
|
|
328
|
+
const call_start = (btn) => {
|
|
329
|
+
data.touchStart?.(self, btn)
|
|
330
|
+
}
|
|
331
|
+
com_btn[touch_start] = call_start
|
|
332
|
+
com_btn.node.on(Node.EventType.TOUCH_START, com_btn[touch_start]);
|
|
333
|
+
}
|
|
334
|
+
touch_start = 'CALL_TOUCH_MOVE'
|
|
335
|
+
if (data.touchMove && !com_btn[touch_start]) {
|
|
336
|
+
com_btn.node.off(Node.EventType.TOUCH_MOVE, com_btn[touch_start]);
|
|
337
|
+
const call_start = (btn) => {
|
|
338
|
+
data.touchMove?.(self, btn)
|
|
339
|
+
}
|
|
340
|
+
com_btn[touch_start] = call_start
|
|
341
|
+
com_btn.node.on(Node.EventType.TOUCH_MOVE, com_btn[touch_start]);
|
|
342
|
+
}
|
|
343
|
+
touch_start = 'CALL_TOUCH_END'
|
|
344
|
+
if (data.touchEnd && !com_btn[touch_start]) {
|
|
345
|
+
com_btn.node.off(Node.EventType.TOUCH_END, com_btn[touch_start]);
|
|
346
|
+
const call_start = (btn) => {
|
|
347
|
+
data.touchEnd?.(self, btn)
|
|
348
|
+
}
|
|
349
|
+
com_btn[touch_start] = call_start
|
|
350
|
+
com_btn.node.on(Node.EventType.TOUCH_END, com_btn[touch_start]);
|
|
351
|
+
}
|
|
352
|
+
touch_start = 'CALL_TOUCH_CANCEL'
|
|
353
|
+
if (data.touchCancel && !com_btn[touch_start]) {
|
|
354
|
+
com_btn.node.off(Node.EventType.TOUCH_CANCEL, com_btn[touch_start]);
|
|
355
|
+
const call_start = (btn) => {
|
|
356
|
+
data.touchCancel?.(self, btn)
|
|
357
|
+
}
|
|
358
|
+
com_btn[touch_start] = call_start
|
|
359
|
+
com_btn.node.on(Node.EventType.TOUCH_CANCEL, com_btn[touch_start]);
|
|
321
360
|
}
|
|
322
|
-
com_btn['btnCall'] = btnCall
|
|
323
|
-
com_btn.node.on(Button.EventType.CLICK, com_btn['btnCall']);
|
|
324
361
|
break;
|
|
325
362
|
case 'cc.ProgressBar':
|
|
326
363
|
if (data.reset) {
|
|
327
364
|
data.reset(self, value, com);
|
|
328
365
|
} else
|
|
329
|
-
if (value) (com as ProgressBar).progress = Number(value) || 0;
|
|
366
|
+
if (value != undefined && value !== null) (com as ProgressBar).progress = Number(value) || 0;
|
|
330
367
|
break;
|
|
331
368
|
case 'cc.Skeleton':
|
|
332
369
|
if (data.reset) {
|
|
333
370
|
data.reset(self, value, com);
|
|
334
371
|
} else
|
|
335
|
-
if (value) (com as sp.Skeleton).skeletonData = value
|
|
372
|
+
if (value != undefined && value !== null) (com as sp.Skeleton).skeletonData = value
|
|
336
373
|
break;
|
|
337
374
|
case 'cc.Slider':
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
data.reset
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
375
|
+
{
|
|
376
|
+
const com_sld = (com as Slider);
|
|
377
|
+
if (data.reset) {
|
|
378
|
+
data.reset(self, value, com);
|
|
379
|
+
} else
|
|
380
|
+
if (value != undefined && value !== null) com_sld.progress = Number(value) || 0;
|
|
381
|
+
|
|
382
|
+
//事件
|
|
383
|
+
const touch_click = 'slideCall'
|
|
384
|
+
if (!com_sld[touch_click]) {
|
|
385
|
+
const sx = data.propertyKey;
|
|
386
|
+
com_sld.node.off("slide", com_sld[touch_click], self)
|
|
387
|
+
tempData.skip = true;
|
|
388
|
+
const slideCall = (slider) => {
|
|
389
|
+
tempData.value = slider.progress
|
|
390
|
+
self.viewModel[sx] = tempData
|
|
391
|
+
data.event?.(self)
|
|
392
|
+
self[`onClick_${sx}`]?.(slider)
|
|
393
|
+
}
|
|
394
|
+
com_sld[touch_click] = slideCall
|
|
395
|
+
com_sld.node.on('slide', slideCall, self);
|
|
396
|
+
}
|
|
352
397
|
}
|
|
353
|
-
com_sld['slideCall'] = slideCall
|
|
354
|
-
com_sld.node.on('slide', slideCall, self);
|
|
355
398
|
break;
|
|
356
399
|
case 'cc.Toggle':
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
data.reset
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
400
|
+
{
|
|
401
|
+
const com_tg = (com as Toggle);
|
|
402
|
+
if (data.reset) {
|
|
403
|
+
data.reset(self, value, com);
|
|
404
|
+
} else
|
|
405
|
+
if (value != undefined && value !== null) com_tg.isChecked = Boolean(value);
|
|
406
|
+
|
|
407
|
+
//事件
|
|
408
|
+
const touch_click = 'toggleCall'
|
|
409
|
+
if (!com_tg[touch_click]) {
|
|
410
|
+
const sx = data.propertyKey;
|
|
411
|
+
com_tg.node.off(Toggle.EventType.TOGGLE, com_tg[touch_click], self)
|
|
412
|
+
tempData.skip = true;
|
|
413
|
+
const toggleCall = (toggle) => {
|
|
414
|
+
tempData.value = toggle.isChecked
|
|
415
|
+
self.viewModel[sx] = tempData
|
|
416
|
+
data.event?.(self)
|
|
417
|
+
self[`onClick_${sx}`]?.(toggle)
|
|
418
|
+
}
|
|
419
|
+
com_tg[touch_click] = toggleCall
|
|
420
|
+
com_tg.node.on(Toggle.EventType.TOGGLE, toggleCall, self);
|
|
421
|
+
}
|
|
371
422
|
}
|
|
372
|
-
com_tg['toggleCall'] = toggleCall
|
|
373
|
-
com_tg.node.on(Toggle.EventType.TOGGLE, toggleCall, self);
|
|
374
423
|
break;
|
|
375
424
|
case 'cc.EditBox':
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
data.reset
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
425
|
+
{
|
|
426
|
+
const com_eb = (com as EditBox);
|
|
427
|
+
if (data.reset) {
|
|
428
|
+
data.reset(self, value, com);
|
|
429
|
+
} else
|
|
430
|
+
if (value != undefined && value !== null) com_eb.string = value?.toString() || '';
|
|
431
|
+
|
|
432
|
+
//事件
|
|
433
|
+
const touch_click = 'ebCall'
|
|
434
|
+
if (!com_eb[touch_click]) {
|
|
435
|
+
const sx = data.propertyKey;
|
|
436
|
+
com_eb.node.off("text-changed", com_eb[touch_click], self)
|
|
437
|
+
tempData.skip = true;
|
|
438
|
+
const ebCall = (editbox: EditBox) => {
|
|
439
|
+
tempData.value = editbox.textLabel.string
|
|
440
|
+
self.viewModel[sx] = tempData
|
|
441
|
+
data.event?.(self)
|
|
442
|
+
self[`onClick_${sx}`]?.(editbox)
|
|
443
|
+
}
|
|
444
|
+
com_eb[touch_click] = ebCall
|
|
445
|
+
com_eb.node.on('text-changed', ebCall, self);
|
|
446
|
+
}
|
|
390
447
|
}
|
|
391
|
-
com_eb['ebCall'] = ebCall
|
|
392
|
-
com_eb.node.on('text-changed', ebCall, self);
|
|
393
448
|
break;
|
|
394
449
|
case 'cc.ToggleContainer':
|
|
395
450
|
{
|
|
@@ -400,6 +455,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
400
455
|
|
|
401
456
|
//事件
|
|
402
457
|
if (com_tgc.checkEvents.length <= 0) {
|
|
458
|
+
const sx = data.propertyKey;
|
|
403
459
|
const funcName = "onClick_ToggleContainer"
|
|
404
460
|
const clickEventHandler = new EventHandler();
|
|
405
461
|
clickEventHandler.target = self.node; // 这个 node 节点是你的事件处理代码组件所属的节点
|
|
@@ -430,7 +486,7 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
430
486
|
// ✅ 关键:不要缓存 count,而是通过 dataPath 动态取值
|
|
431
487
|
const getLatestDataLength = () => {
|
|
432
488
|
const latestValue = self._getNestedValue(self, data.dataPath);
|
|
433
|
-
return
|
|
489
|
+
return latestValue ? latestValue.length : 0;
|
|
434
490
|
};
|
|
435
491
|
|
|
436
492
|
if (com_list.isInit) {
|
|
@@ -481,13 +537,21 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
481
537
|
// const width = 100
|
|
482
538
|
// const height = 163
|
|
483
539
|
// layout.itemSize = math.size(width, height)
|
|
484
|
-
table_collection.layout = data.layout()
|
|
540
|
+
table_collection.layout = data.layout(self)
|
|
485
541
|
// 注册列表内需要使用的 cell 节点类型
|
|
486
542
|
// 这个演示是通过编辑器绑定的,可以查看场景内 list 节点里的 register cells 配置
|
|
487
543
|
// this.table_collection.register('cell', () => instantiate('your cell prefab'))
|
|
488
544
|
// 确定列表内一共需要显示多少条内容
|
|
489
545
|
// table_collection.isCenterShow = false;//少于宽度,居中显示
|
|
490
|
-
table_collection.numberOfItems = () =>
|
|
546
|
+
table_collection.numberOfItems = () => {
|
|
547
|
+
const count = data.numberOfItems ? data.numberOfItems(self) : getLatestDataLength()
|
|
548
|
+
if (table_collection.layout instanceof YXPagelayout) {
|
|
549
|
+
table_collection.layout.dataCount = count
|
|
550
|
+
return count * 3
|
|
551
|
+
} else {
|
|
552
|
+
return count
|
|
553
|
+
}
|
|
554
|
+
}
|
|
491
555
|
table_collection.cellForItemAt = (indexPath, collectionView) => {
|
|
492
556
|
return data.cellForItemAt(self, indexPath, collectionView as any) // 返回这个节点给列表显示
|
|
493
557
|
}
|
|
@@ -503,8 +567,9 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
503
567
|
table_collection.reloadData()
|
|
504
568
|
}
|
|
505
569
|
break;
|
|
506
|
-
default:
|
|
507
|
-
console.error(`请检查类型: ${data.type}`);
|
|
570
|
+
default: {
|
|
571
|
+
if (com) console.error(`请检查类型: ${data.type}`);
|
|
572
|
+
}
|
|
508
573
|
}
|
|
509
574
|
|
|
510
575
|
}
|
|
@@ -516,33 +581,11 @@ function updateStatus(data: IBindingData, com: Component, value: any, self: any)
|
|
|
516
581
|
* 响应式数据装饰器
|
|
517
582
|
* 自动将属性转为响应式对象,并使用属性名作为路径前缀
|
|
518
583
|
*/
|
|
519
|
-
export function BindViewModel<T extends new () => any>(constructor: T) {
|
|
520
|
-
return function (target: any, propertyKey: string) {
|
|
521
|
-
const originalOnLoad = target.constructor.prototype.onLoad;
|
|
522
|
-
target.constructor.prototype.onLoad = function () {
|
|
523
|
-
// 创建实例并转为响应式
|
|
524
|
-
const instance = new constructor();
|
|
525
|
-
this[propertyKey] = this._makeReactive(instance, propertyKey);
|
|
526
|
-
originalOnLoad?.call(this);
|
|
527
|
-
};
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
584
|
|
|
531
585
|
// 定义装饰器
|
|
532
586
|
export function Ref(target: any, propertyKey: string) {
|
|
533
|
-
|
|
534
587
|
const className = js.getClassName(target)
|
|
535
588
|
if (!refMap.has(className)) { refMap.set(className, []) }
|
|
536
589
|
const refList = refMap.get(className)
|
|
537
|
-
if (refList.length <= 0) {
|
|
538
|
-
const originalOnLoad = target.constructor.prototype.onLoad;
|
|
539
|
-
target.constructor.prototype.onLoad = function (this: any) {
|
|
540
|
-
this.initReferenceCollector();
|
|
541
|
-
this.defineProperty(propertyKey);
|
|
542
|
-
originalOnLoad?.call(this);
|
|
543
|
-
this.onLoadFinish();
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
}
|
|
547
590
|
refList.push(propertyKey)
|
|
548
591
|
}
|
|
@@ -522,6 +522,20 @@ export abstract class YXLayout {
|
|
|
522
522
|
* 列表组件销毁时执行
|
|
523
523
|
*/
|
|
524
524
|
onDestroy() { }
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
//#region 新加
|
|
528
|
+
/**
|
|
529
|
+
* 转换为真实索引
|
|
530
|
+
* 列表数量大小为 3 倍实际数据数量,需要通过求余方式获取数据,避免数组越界
|
|
531
|
+
*/
|
|
532
|
+
dataCount: number = 0
|
|
533
|
+
originIndex(index: number): number {
|
|
534
|
+
return 0
|
|
535
|
+
}
|
|
536
|
+
originIndexCount(): number {
|
|
537
|
+
return this.dataCount * 3
|
|
538
|
+
}
|
|
525
539
|
}
|
|
526
540
|
|
|
527
541
|
/**
|
|
@@ -100,11 +100,18 @@ enum _yx_flow_layout_section_kinds {
|
|
|
100
100
|
*/
|
|
101
101
|
export class YXFlowLayout extends YXBinaryLayout {
|
|
102
102
|
|
|
103
|
-
/**
|
|
104
|
-
* 是否开启分页滚动效果
|
|
105
|
-
*/
|
|
106
|
-
pagingEnabled: boolean = false
|
|
107
103
|
|
|
104
|
+
// pagingEnabled: boolean = false
|
|
105
|
+
_pagingEnabled: boolean = false
|
|
106
|
+
set pagingEnabled(value: boolean) {
|
|
107
|
+
this._pagingEnabled = value
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 是否开启分页滚动效果
|
|
111
|
+
*/
|
|
112
|
+
get pagingEnabled() {
|
|
113
|
+
return this._pagingEnabled
|
|
114
|
+
}
|
|
108
115
|
/**
|
|
109
116
|
* 分页吸附动画时间
|
|
110
117
|
*/
|
|
@@ -119,7 +126,7 @@ export class YXFlowLayout extends YXBinaryLayout {
|
|
|
119
126
|
/**
|
|
120
127
|
* 约束优先级
|
|
121
128
|
*/
|
|
122
|
-
priority: _yx_flow_layout_priority = YXFlowLayout.Priority.
|
|
129
|
+
priority: _yx_flow_layout_priority = YXFlowLayout.Priority.SIDE
|
|
123
130
|
static Priority = _yx_flow_layout_priority
|
|
124
131
|
|
|
125
132
|
/**
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { ScrollView } from "cc";
|
|
2
|
+
import { YXFlowLayout } from "./yx-flow-layout";
|
|
3
|
+
import { YXCollectionView, YXIndexPath } from "./yx-collection-view";
|
|
4
|
+
import { math } from "cc";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export class YXPagelayout extends YXFlowLayout {
|
|
8
|
+
|
|
9
|
+
_pagingEnabledLoop = false
|
|
10
|
+
set pagingEnabledLoop(value: boolean) {
|
|
11
|
+
this._pagingEnabledLoop = value
|
|
12
|
+
}
|
|
13
|
+
get pagingEnabledLoop() {
|
|
14
|
+
return this._pagingEnabledLoop
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 记录当前页面
|
|
18
|
+
*/
|
|
19
|
+
pageIdx: number = -1
|
|
20
|
+
|
|
21
|
+
collectionView: YXCollectionView
|
|
22
|
+
scrollView: ScrollView;
|
|
23
|
+
dataCount: number = 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
pageAction: (idx: number) => void
|
|
27
|
+
loop(collectionView: YXCollectionView) {
|
|
28
|
+
/**
|
|
29
|
+
* 无限轮播实现思路
|
|
30
|
+
* 列表容器总体大小为 数据条数 * 3 的大小,每次在滚动结束的时候,偏移量总是复位到中间的位置,以此来实现无限滚动
|
|
31
|
+
* 比如原始数据 [ 0,1,2 ],实际上在列表中为 [ 0,1,2, 0,1,2, 0,1,2 ],每次滑动结束之后位置总是复位到中间区域
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
// 注册列表内需要使用的 cell 节点类型
|
|
35
|
+
// 这个演示是通过编辑器绑定的,可以查看场景内 list 节点里的 register cells 配置
|
|
36
|
+
// this.listComp.register(`cell`, () => instantiate('your cell prefab'))
|
|
37
|
+
this.collectionView = collectionView
|
|
38
|
+
this.scrollView = collectionView.scrollView
|
|
39
|
+
this.scrollView.node.on(ScrollView.EventType.SCROLLING, this.checkPageChange, this)
|
|
40
|
+
this.scrollView.node.on(ScrollView.EventType.SCROLL_ENDED, this.resetOffset, this)
|
|
41
|
+
this.pagingEnabled = true;
|
|
42
|
+
this.collectionView.recycleInterval = 0
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
onDestroy(): void {
|
|
46
|
+
this.scrollView.node.off(ScrollView.EventType.SCROLLING, this.checkPageChange, this)
|
|
47
|
+
this.scrollView.node.off(ScrollView.EventType.SCROLL_ENDED, this.resetOffset, this)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获取当前页面索引
|
|
52
|
+
* @returns
|
|
53
|
+
*/
|
|
54
|
+
getCurrentPageIndex(): number {
|
|
55
|
+
let offset = this.collectionView.scrollView.getScrollOffset()
|
|
56
|
+
offset.x = - offset.x
|
|
57
|
+
let idx = Math.round(offset.x / this.collectionView.scrollView.view.width)
|
|
58
|
+
return idx
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* 检查页面变化
|
|
63
|
+
*/
|
|
64
|
+
checkPageChange() {
|
|
65
|
+
const idx = this.getCurrentPageIndex()
|
|
66
|
+
if (this.pageIdx !== idx) {
|
|
67
|
+
this.pageIdx = idx
|
|
68
|
+
// 走到这里表示页面发生变化,可以处理需要处理的逻辑
|
|
69
|
+
this.pageAction && this.pageAction(this.originIndex(this.pageIdx))
|
|
70
|
+
console.log(this.originIndex(this.pageIdx));
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 使列表复位到中间区域
|
|
77
|
+
*/
|
|
78
|
+
resetOffset() {
|
|
79
|
+
let offset = this.scrollView.getScrollOffset()
|
|
80
|
+
offset.x = - offset.x
|
|
81
|
+
let idx = Math.round(offset.x / this.scrollView.view.width) % this.dataCount
|
|
82
|
+
offset.x = this.scrollView.view.width * (this.dataCount + idx)
|
|
83
|
+
this.scrollView.scrollToOffset(offset)
|
|
84
|
+
// 直接设置滚动位置不会触发刷新,这里强制刷新一下
|
|
85
|
+
this.collectionView.markForUpdateVisibleData(true)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 转换为真实索引
|
|
90
|
+
* 列表数量大小为 3 倍实际数据数量,需要通过求余方式获取数据,避免数组越界
|
|
91
|
+
*/
|
|
92
|
+
originIndex(index: number): number {
|
|
93
|
+
return index % this.dataCount
|
|
94
|
+
}
|
|
95
|
+
originIndexCount(): number {
|
|
96
|
+
return this.dataCount * 3
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
@@ -28,7 +28,7 @@ export class ListViewPage extends ListView {
|
|
|
28
28
|
this.node.on(ScrollView.EventType.SCROLL_BEGAN, this.onTouchStart, this);
|
|
29
29
|
this.node.on(ScrollView.EventType.TOUCH_UP, this.onTouchEnd, this);
|
|
30
30
|
this.node.on(ScrollView.EventType.SCROLLING, this._scrollViewDidScroll, this);
|
|
31
|
-
this.node.on(Node.EventType.TOUCH_CANCEL, this.
|
|
31
|
+
this.node.on(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
|
|
32
32
|
|
|
33
33
|
//ScrollView.EventType
|
|
34
34
|
}
|
|
@@ -83,7 +83,9 @@ export class ListViewPage extends ListView {
|
|
|
83
83
|
this.content = content
|
|
84
84
|
viewMask.getComponent(Widget).updateAlignment()
|
|
85
85
|
}
|
|
86
|
+
|
|
86
87
|
this.contentUT = this.content.getComponent(UITransform)
|
|
88
|
+
let count = 0
|
|
87
89
|
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
88
90
|
this.contentUT.anchorX = this.config.isLoop ? 0.5 : 0
|
|
89
91
|
this.contentUT.anchorY = 0.5
|
|
@@ -91,10 +93,13 @@ export class ListViewPage extends ListView {
|
|
|
91
93
|
this.contentUT.anchorX = 0.5
|
|
92
94
|
this.contentUT.anchorY = this.config.isLoop ? 0.5 : 1
|
|
93
95
|
}
|
|
96
|
+
|
|
94
97
|
this.nodeUT.setAnchorPoint(0.5, 0.5)
|
|
95
98
|
const mask_node = this.content.parent.getComponent(UITransform)
|
|
96
99
|
this.contentUT.contentSize = new Size(mask_node.width, mask_node.height)
|
|
97
100
|
this.scrollTo(v2(0))
|
|
101
|
+
|
|
102
|
+
|
|
98
103
|
}
|
|
99
104
|
initView() {
|
|
100
105
|
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
@@ -119,7 +124,7 @@ export class ListViewPage extends ListView {
|
|
|
119
124
|
this.node.off(Node.EventType.TOUCH_START, this.onTouchStart, this);
|
|
120
125
|
this.node.off(Node.EventType.TOUCH_MOVE, this.onTouchMove, this);
|
|
121
126
|
this.node.off(Node.EventType.TOUCH_END, this.onTouchEnd, this);
|
|
122
|
-
this.node.off(Node.EventType.TOUCH_CANCEL, this.
|
|
127
|
+
this.node.off(Node.EventType.TOUCH_CANCEL, this.onTouchCancel, this);
|
|
123
128
|
|
|
124
129
|
}
|
|
125
130
|
|
|
@@ -208,6 +213,7 @@ export class ListViewPage extends ListView {
|
|
|
208
213
|
|
|
209
214
|
|
|
210
215
|
_reloadData() {
|
|
216
|
+
this.stopAutoScroll()
|
|
211
217
|
let numberOfItems = this.delegate.numberOfItems();
|
|
212
218
|
this.numberOfItems = numberOfItems;
|
|
213
219
|
|
|
@@ -235,7 +241,7 @@ export class ListViewPage extends ListView {
|
|
|
235
241
|
}
|
|
236
242
|
let offsetMax = this.getMaxScrollOffset();
|
|
237
243
|
|
|
238
|
-
|
|
244
|
+
|
|
239
245
|
|
|
240
246
|
this.scrollToOffset(v2(-offset.x, offset.y))
|
|
241
247
|
this.isReload = true;
|
|
@@ -296,6 +302,7 @@ export class ListViewPage extends ListView {
|
|
|
296
302
|
start_pos = this.getShowRowListPos()
|
|
297
303
|
|
|
298
304
|
this.visbleCellList.forEach((cell, index) => {
|
|
305
|
+
console.log(`cell.row:${cell.row_data},${cell.row}`)
|
|
299
306
|
let x = 0;
|
|
300
307
|
if (lastCell) {
|
|
301
308
|
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
@@ -358,27 +365,40 @@ export class ListViewPage extends ListView {
|
|
|
358
365
|
target_pos = v3(0, 0, 0)
|
|
359
366
|
currentRow = 0
|
|
360
367
|
}
|
|
368
|
+
|
|
361
369
|
const count = Math.max(showChount - (showChount - currentRow), 0);
|
|
362
370
|
|
|
363
371
|
const width = this.getWidth() + this.config.cellSpace;
|
|
364
372
|
const max_height = width * count
|
|
365
373
|
let start = 0
|
|
366
374
|
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
start =
|
|
375
|
+
if (target_pos) {
|
|
376
|
+
|
|
377
|
+
start = (target_pos.x - max_height)
|
|
378
|
+
// if (max_height === 0) { start = 0 }
|
|
379
|
+
if (start <= 0) {
|
|
380
|
+
start = start + this.getWidth() * 0.5
|
|
381
|
+
}
|
|
382
|
+
if (this.lastCellCount <= 0) {
|
|
383
|
+
start += this.config.cellSpaceLeft
|
|
384
|
+
}
|
|
370
385
|
}
|
|
371
|
-
|
|
372
|
-
start += this.config.cellSpaceLeft
|
|
386
|
+
else {
|
|
387
|
+
start += this.config.cellSpaceLeft + this.getWidth() * 0.5
|
|
373
388
|
}
|
|
374
389
|
} else {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
390
|
+
if (target_pos) {
|
|
391
|
+
start = (target_pos.y + max_height)
|
|
392
|
+
if (start >= 0) {
|
|
393
|
+
start = start - this.getWidth() * 0.5
|
|
394
|
+
}
|
|
395
|
+
if (this.lastCellCount <= 0) {
|
|
396
|
+
start -= this.config.cellSpaceLeft
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
start += this.config.cellSpaceLeft + this.getWidth() * 0.5
|
|
381
400
|
}
|
|
401
|
+
|
|
382
402
|
}
|
|
383
403
|
|
|
384
404
|
return start
|
|
@@ -392,13 +412,12 @@ export class ListViewPage extends ListView {
|
|
|
392
412
|
const count_n = this.numberOfItems - this.max_row_data;
|
|
393
413
|
let row = count_n > 0 ? this.min_row_data : Math.max(this.min_row_data - (-count_n + 1), 0)
|
|
394
414
|
if (this.visbleCellList.length > 0) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
415
|
+
const ok_1 = this.numberOfItems > this.config.maxShowCount
|
|
416
|
+
const ok_2 = this.currentRow < this.numberOfItems - 1
|
|
417
|
+
const ok_3 = this.max_row_data + 1 < this.numberOfItems
|
|
418
|
+
const ok_4 = (this.currentRow === this.visbleCellList[this.visbleCellList.length - 1].row_data || this.currentRow === this.visbleCellList[this.visbleCellList.length - 2].row_data)
|
|
398
419
|
|
|
399
|
-
|
|
400
|
-
this.currentRow === this.visbleCellList[this.visbleCellList.length - 2].row_data)
|
|
401
|
-
) {
|
|
420
|
+
if (ok_1 && ok_2 && ok_3 && ok_4 && row != 0) {
|
|
402
421
|
row += 1;
|
|
403
422
|
this.max_row_data += 1
|
|
404
423
|
//console.error("走了", this.max_row_data)
|
|
@@ -457,6 +476,22 @@ export class ListViewPage extends ListView {
|
|
|
457
476
|
this.touchEnd(event, false)
|
|
458
477
|
}
|
|
459
478
|
|
|
479
|
+
}
|
|
480
|
+
onTouchCancel(event: EventTouch) {
|
|
481
|
+
|
|
482
|
+
if (this.config.isPage)
|
|
483
|
+
this.onTouchEnd(event)
|
|
484
|
+
|
|
485
|
+
// const of = this.getScrollOffset()
|
|
486
|
+
// if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
487
|
+
// if (of.x < 0)
|
|
488
|
+
// this.onTouchEnd(event)
|
|
489
|
+
// } else {
|
|
490
|
+
// if (of.x < 0)
|
|
491
|
+
// this.onTouchEnd(event)
|
|
492
|
+
// }
|
|
493
|
+
|
|
494
|
+
|
|
460
495
|
}
|
|
461
496
|
|
|
462
497
|
touchEnd(event: EventTouch, isInit) {
|
|
@@ -637,6 +672,7 @@ export class ListViewPage extends ListView {
|
|
|
637
672
|
_scrollViewDidScrollPage(is_move = false) {
|
|
638
673
|
this._updateMaxNode()
|
|
639
674
|
const of = this.getScrollOffset();
|
|
675
|
+
// console.log(of)
|
|
640
676
|
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
641
677
|
this.velocity = Math.abs((of.x - this.lastOffset.x))
|
|
642
678
|
} else {
|
|
@@ -33,29 +33,49 @@ export class TableView extends Component {
|
|
|
33
33
|
return this.delegate ? true : false;
|
|
34
34
|
}
|
|
35
35
|
finish: Function;
|
|
36
|
+
isOnload = false;
|
|
36
37
|
// view: Node;
|
|
37
38
|
protected onLoad(): void {
|
|
38
39
|
if (this.config.isLoop) {
|
|
39
40
|
this.scrollView = this.node.addComponent(ListViewPageLoop)
|
|
41
|
+
this.scrollView.elastic = false
|
|
40
42
|
} else {
|
|
41
43
|
this.scrollView = this.node.addComponent(ListViewPage)
|
|
44
|
+
this.scrollView.elastic = this.config.isPage ? false : true
|
|
42
45
|
}
|
|
43
46
|
this.scrollView.elastic = false
|
|
47
|
+
|
|
44
48
|
this.scrollView.delegate = this.delegate;
|
|
45
49
|
this.scrollView.config = this.config;
|
|
46
50
|
this.scrollView.init();
|
|
47
|
-
this.
|
|
51
|
+
this.isOnload = true
|
|
52
|
+
if (this.finish) {
|
|
53
|
+
this.finish()
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
}
|
|
49
57
|
init(delegate: IListView) {
|
|
50
58
|
this.delegate = delegate
|
|
51
59
|
//解决一些设置时间点慢的问题
|
|
52
60
|
if (this.scrollView) {
|
|
53
61
|
this.scrollView.delegate = delegate
|
|
62
|
+
const itemSize = this.delegate.itemSize();
|
|
63
|
+
let count = 0
|
|
64
|
+
if (this.config.scrollDirection === collection_view_scroll_direction.HORIZONTAL) {
|
|
65
|
+
count = this.scrollView.nodeUT.width / (itemSize.width + this.config.cellSpace)//+ this.config.cellSpaceLeft + this.config.cellSpaceRight
|
|
66
|
+
} else {
|
|
67
|
+
count = this.scrollView.nodeUT.height / (itemSize.height + this.config.cellSpace)//+ this.config.cellSpaceLeft + this.config.cellSpaceRight
|
|
68
|
+
}
|
|
69
|
+
this.config.maxShowCount = Math.max(Math.floor(count) + 3, this.config.maxShowCount)
|
|
70
|
+
console.log("maxShowCount", this.config.maxShowCount)
|
|
54
71
|
}
|
|
55
|
-
|
|
56
72
|
}
|
|
57
73
|
onLoadFinish(call: () => void) {
|
|
58
74
|
this.finish = call
|
|
75
|
+
if (this.isOnload) {
|
|
76
|
+
this.finish?.()
|
|
77
|
+
this.finish = null
|
|
78
|
+
}
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
public reload() {
|