import EventMng from "../../manager/EventMng"; import LevelRender from "../compment/LevelRender"; import { AutowiredItem } from "./Autowire"; import { BtnEvent } from "./mvc/FguiViewCtrl"; export enum VirtualListType { /** * 实列表 */ Real = 1, /** * 虚拟列表(非循环 */ Virtual = 2, /** * 虚拟循环列表 */ VirtualAndLoop = 3, } export class ListUtil { // static readonly TweenInTime = 0.19; static readonly TweenInTime = 0.5; static readonly TweenDelayTime = 0.11; dataList: any[]; gList: fgui.GList; param: any; private needTween: number; private aniName: string; private delay: number = ListUtil.TweenDelayTime; /** * 列表管理类(需要注意同一个fgui资源不应该被不同的类重复拓展) * @param glist 管理的列表 * @param uiClass 拓展的列表资源类(自己定义一个类,继承Itemrender类) * @param listType 列表类型,见ListType 1.(默认开启虚拟列表,如果要开启虚拟列表,必须设置滚动 2.(虚拟循环列表不支持横向或纵向流动 * @param levelrender 开启分层渲染,(内容物包含遮罩的禁止使用!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!) */ constructor(glist: fgui.GList, uiClass: (new () => ItemRender) | (new () => ItemLabelRender) = null, listType: VirtualListType = VirtualListType.Virtual, levelrender: boolean = false) { this.gList = glist; if (levelrender) glist._container.addComponent(LevelRender); if (uiClass) { let item = glist.getFromPool(); if (!item) { if (CC_PREVIEW) console.error("列表内没有添加默认资源"); return; } if (item.packageItem.extensionType && item.packageItem.extensionType != uiClass) { if (CC_PREVIEW) console.warn(`列表${this.gList.name}内的默认资源资源${item.resourceURL}, 已经被`, item.packageItem.extensionType, "拓展"); return; } item.packageItem.extensionType = uiClass; fgui.UIObjectFactory.extensions[item.resourceURL] = uiClass; } switch (listType) { case VirtualListType.Virtual: this.gList.setVirtual(); break; case VirtualListType.VirtualAndLoop: this.gList.setVirtualAndLoop(); break; } } /** * 列表内容可变时需要自己预先根据url预先拓展(fgui.UIObjectFactory.setExtension * @param cb 提供item的url回调 * @param target 绑定 */ setItemProvider(cb: (index: number) => string, target: any = this) { this.gList.itemProvider = cb.bind(target); } /** * 刷新列表 * @param list 数据 * @param param 额外参数 */ refreshItems(list: any[], param?: any) { this.dataList = list; this.param = param; this.gList.itemRenderer = this.refreshItem.bind(this); this.gList.numItems = list.length; this.gList.ensureBoundsCorrect(); this.clearTween(); } private refreshItem(index: number, render: ItemRender) { let data = this.dataList[index]; try { render.__refreshData(data, index, this.param, this.needTween, this.aniName, this.delay); } catch (err) { if (CC_PREVIEW) console.warn(err); } } setTween(line: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) { this.needTween = line; this.aniName = aniName; this.delay = delay; } clearTween() { this.needTween = 0; this.aniName = null; this.delay = ListUtil.TweenDelayTime; } } export abstract class ItemRender extends fairygui.GButton implements AutowiredItem { __autowired: string[]; private __tween__: cc.Tween; index: number; __AutoGetItem() { this.__autowired?.forEach((key: string) => { this[key] = this.getChild(key); }); } __refreshData(data: any, index: number, param: any, needTween: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) { if (needTween) this.__ShowTween(index, needTween, aniName, delay); else this.__clearTween(); this.index = index; this.setData(data, index, param); } /** * @param data 列表数据 * @param index 列表内资源对应下标,从0开始 * @param param 额外参数 */ abstract setData(data: any, index?: number, param?: any); /**通知事件列表 */ private _notifyEventList: Map = new Map(); //计时器ID列表 private m_Timers: Set = new Set(); /** 按钮点击注册器 */ private btnClicks: BtnEvent[] = []; protected onConstruct(): void { this.__AutoGetItem(); this.onInit(); } protected onEnable(): void { this.onShow(); } protected onDisable(): void { this.offEvent(); this.RemoveAllClick(); this.RemoveTimers(); this.__clearTween(); this.onHide(); } onShow() { } onHide() { } onInit() { } /** * 获取所有控制器并赋值 */ initControllers() { for (let i of this.controllers) { this[i.name] = i; } } offEvent() { try { let self = this; this._notifyEventList.forEach((f, key) => { EventMng.off(key, f, self); }, this); this._notifyEventList.clear(); } catch (error) { if (CC_PREVIEW) console.error("onDisable->" + error); } } /**注册notice事件,disable的时候会自动移除 */ initEvent(eventName: string, cb: Function) { if (this._notifyEventList.get(eventName) != null) return; this._notifyEventList.set(eventName, cb); EventMng.on(eventName, cb, this); } /** * 增加定时器 * @param callback * @param delta 单位毫秒ms */ AddTimer(callback: Function, delta: number) { let timer = setInterval(() => { callback.apply(this); }, delta); this.m_Timers.add(timer); } /** 移除所有定时器 */ RemoveTimers() { this.m_Timers.forEach((element) => { clearInterval(element); }); this.m_Timers.clear(); } /** * 一次性定时器 * @param callback * @param delta 单位毫秒ms */ AddTimerOnce(callback: Function, delta: number) { let timer = setInterval(() => { clearInterval(timer); this.m_Timers.delete(timer); callback(); }, delta); this.m_Timers.add(timer); return timer; } RegisterClick(btn: fairygui.GObject, func: Function) { btn.onClick(func, this); this.btnClicks.push({ btn: btn, func: func }); } RemoveAllClick() { this.btnClicks.forEach((element) => { element.btn.offClick(element.func, this); }); } private __fguiTweentimer = null; private __ShowTween(index: number, needTween: number, aniName: string = null, delayTime: number = ListUtil.TweenDelayTime) { if (this.__tween__) { this.__tween__.stop(); } let delay = Math.floor(index / needTween) * delayTime; if (aniName != null) { if (this.__fguiTweentimer) clearInterval(this.__fguiTweentimer); this.alpha = 0; this.__fguiTweentimer = this.AddTimerOnce(() => { this.alpha = 1; this.getTransition(aniName).play(); this.__fguiTweentimer = null; }, delay * 1000); } else { this.alpha = 0; this.__tween__ = cc .tween(this as fairygui.GObject) .delay(delay) .to(ListUtil.TweenInTime, { alpha: 1, }) .call(() => { this.alpha = 1; }) .start(); } } private __clearTween() { this.__tween__?.stop(); this.alpha = 1; } } export abstract class ItemLabelRender extends fairygui.GLabel implements AutowiredItem { __autowired: string[]; private __tween__: cc.Tween; __AutoGetItem() { this.__autowired?.forEach((key: string) => { this[key] = this.getChild(key); }); } __refreshData(data: any, index: number, param: any, needTween: number, aniName: string = null, delay: number = ListUtil.TweenDelayTime) { if (needTween > 0) this.__ShowTween(index, needTween, aniName, delay); else this.__clearTween(); this.setData(data, index, param); } /** * @param data 列表数据 * @param index 列表内资源对应下标,从0开始 * @param param 额外参数 */ abstract setData(data: any, index?: number, param?: any); /**通知事件列表 */ private _notifyEventList: Map = new Map(); //计时器ID列表 private m_Timers: Set = new Set(); /** 按钮点击注册器 */ private btnClicks: BtnEvent[] = []; protected onConstruct(): void { this.__AutoGetItem(); this.onInit(); } protected onEnable(): void { this.onShow(); } protected onDisable(): void { this.offEvent(); this.RemoveAllClick(); this.RemoveTimers(); this.__clearTween(); this.onHide(); } onShow() { } onHide() { } onInit() { } /** * 获取所有控制器并赋值 */ initControllers() { for (let i of this.controllers) { this[i.name] = i; } } offEvent() { try { let self = this; this._notifyEventList.forEach((f, key) => { EventMng.off(key, f, self); }, this); this._notifyEventList.clear(); } catch (error) { if (CC_PREVIEW) console.error("onDisable->" + error); } } /**注册notice事件,disable的时候会自动移除 */ initEvent(eventName: string, cb: Function) { if (this._notifyEventList.get(eventName) != null) return; this._notifyEventList.set(eventName, cb); EventMng.on(eventName, cb, this); } /** * 增加定时器 * @param callback * @param delta 单位毫秒ms */ AddTimer(callback: Function, delta: number) { let timer = setInterval(() => { callback.apply(this); }, delta); this.m_Timers.add(timer); } /** 移除所有定时器 */ RemoveTimers() { this.m_Timers.forEach((element) => { clearInterval(element); }); this.m_Timers.clear(); } /** * 一次性定时器 * @param callback * @param delta 单位毫秒ms */ AddTimerOnce(callback: Function, delta: number) { let timer = setInterval(() => { clearInterval(timer); this.m_Timers.delete(timer); callback(); }, delta); this.m_Timers.add(timer); return timer; } RegisterClick(btn: fairygui.GObject, func: Function) { btn.onClick(func, this); this.btnClicks.push({ btn: btn, func: func }); } RemoveAllClick() { this.btnClicks.forEach((element) => { element.btn.offClick(element.func, this); }); } private __fguiTweentimer = null; private __ShowTween(index: number, needTween: number, aniName: string = null, delayTime: number = ListUtil.TweenDelayTime) { if (this.__tween__) { this.__tween__.stop(); } let delay = Math.floor(index / needTween) * delayTime; if (aniName != null) { if (this.__fguiTweentimer) clearInterval(this.__fguiTweentimer); this.alpha = 0; this.__fguiTweentimer = this.AddTimerOnce(() => { this.alpha = 1; this.getTransition("aniName")?.play(); this.__fguiTweentimer = null; }, delay * 1000); } else { this.alpha = 0; this.__tween__ = cc .tween(this as fairygui.GObject) .delay(delay) .to(ListUtil.TweenInTime, { alpha: 1, }) .call(() => { this.alpha = 1; }) .start(); } } private __clearTween() { this.__tween__?.stop(); this.__tween__ = null; this.alpha = 1; } }