根據以往經驗我開發了三種類型的管理器,隊列管理器,棧式管理器,單UI管理器。node
第一層:使用單UI管理器用於管理,大廳,遊戲等一級界面。微信
第二層:使用棧式管理器 管理二級界面網絡
第三層:使用隊列管理器用於管理進入遊戲時彈出的各類活動面板。ide
第四層:使用棧式管理器用於管理toast,tip等提示框。函數
第五層:爲最上層,使用棧式管理器,用於管理教學,對話界面和網絡屏蔽層等。
特別說明:好比將一個戰鬥UI分爲戰鬥層和按鈕層,這個不屬於管理器範疇。優化
結構圖
ui
export default interface LayerInterface { exit(): void; /** * 設置組件是否可見 * @param f */ setVisible(f: boolean): void; /** * 設置組件節點的zroder * @param order */ setOrder(order: number): void; /** * * @param t 管理器層級 */ setUIIndex(t: number): void; getUIIndex(): number; /** * 得到組件的node */ getNode(): any; isLoad(): boolean; }
import LayerInterface from "./LayerInterface"; export default abstract class LayerManager { //根節點 protected root: any; protected list: LayerInterface[] //管理器中的內容是否能夠被刪除 protected popFlag: boolean = false; protected zOrder: number = 1; constructor(zOrder: number = 1, canPop: boolean = true) { this.list = [] this.zOrder = zOrder; this.popFlag = canPop; } init(node: any) { this.root = node; } setZOrder(order: number) { this.zOrder = order; } getZOrder(): number { return this.zOrder; } canPop() { return this.popFlag; } //ui數量 count() { return this.list.length; } setVisible(flag: boolean) { for (let index = 0; index < this.list.length; index++) { const element = this.list[index]; element.setVisible(flag) } } //判斷某個ui是否存在 has(layer: LayerInterface) { for (let index = 0; index < this.list.length; index++) { const element = this.list[index]; if (layer === element) { return true; } } return false; } //添加layer abstract pushView(layer: LayerInterface): void; // 移除layer abstract popView(view: LayerInterface): boolean; //刪除指定ui removeView(layer: LayerInterface): boolean { // logInfo(' LayerManger removeView ') for (let index = 0; index < this.list.length; index++) { const element: LayerInterface = this.list[index]; if (layer === element) { element.exit(); this.list.splice(index, 1); return true; } } // console.warn(' removeView is not have ', layer, ' list ', this.list) return false; } //清空全部ui clear() { // logInfo(' LayerManger clear ') for (let index = 0; index < this.list.length; index++) { const element: LayerInterface = this.list[index]; element.exit(); } this.list.length = 0; } }
import LayerManager from "./LayerManager"; import LayerInterface from "./LayerInterface"; export default class SingleManager extends LayerManager { pushView(view: LayerInterface) { if (this.list.length > 0) { this.removeView(this.list.shift()) } this.list.push(view); view.setOrder(this.zOrder); this.root.addChild(view.getNode()) } //不支持主動移除 popView(view: LayerInterface) { return false; } }
import LayerManager from "./LayerManager" import LayerInterface from "./LayerInterface" export default class StackLayerManager extends LayerManager { //添加layer pushView(view: LayerInterface) { this.list.push(view); view.setOrder(this.zOrder) this.root.addChild(view.getNode()) } // 移除layer popView(view: LayerInterface): boolean { if (this.list.length > 0) { let layerInfo = this.list.pop(); layerInfo.exit(); return true; } else { return false; } } }
import LayerManager from "./LayerManager" import LayerInterface from "./LayerInterface"; export default class QueueLayerManager extends LayerManager { //添加layer pushView(view: LayerInterface) { this.list.push(view); if (this.list.length == 1) { this.show(view); } } show(view: LayerInterface) { view.setOrder(this.zOrder); this.root.addChild(view.getNode()) } // 移除layer popView(view: any): boolean { if (this.list.length > 0) { let layerInfo = this.list.shift(); layerInfo.exit(); if (this.list.length > 0) { this.show(this.list[0]); } return true; } else { return false; } } }
import LayerManager from "./LayerManager" import EventDispatcher from "../event/EventDispatcher"; import GlobalEvent from "../event/GlobalEvent"; import LayerInterface from "./LayerInterface"; export default class UIManager extends EventDispatcher { private managers: LayerManager[] = []; private root: any; private static ins: UIManager; static instance(): UIManager { if (!UIManager.ins) { UIManager.ins = new UIManager(); } return UIManager.ins; } constructor() { super(); this.managers = []; } /** * * @param uiIndex * @param flag */ setVisible(uiIndex: number, flag: boolean) { // logInfo('setVisible ', uiIndex, flag) this.managers[uiIndex].setVisible(flag) } init(node: any) { this.root = node } setManager(index: number, manager: LayerManager) { this.managers[index] = manager; this.managers[index].init(this.root) } /** * 清除UI */ clear() { for (let index = this.managers.length - 1; index >= 0; index--) { const manager = this.managers[index]; if (manager.canPop() && manager.count() > 0) { manager.clear() } } } //添加UI pushView(layer: LayerInterface) { if (layer) { let uiIndex = layer.getUIIndex() let manager = this.managers[uiIndex]; if (!manager) { console.log(' manager is null ', layer) return; } layer.setUIIndex(uiIndex) manager.pushView(layer); this.getOpenUICount(); } } /** * 此方法用於關閉界面,爲了兼容Android的back鍵 因此layer有爲null的狀況。 * 若是 返回false 代表已經沒有界面能夠彈出,此時就能夠彈出是否退出遊戲提示了。 * @param layer */ popView(layer?: LayerInterface) { // console.log('popView layer is ', layer) let flag = false; if (layer) { let index: number = layer.getUIIndex() // console.log(' popView index is ', index, ' layer is ', layer) let manger = this.managers[index]; if (!manger) { // console.log(' popView layer is not found type is ', type) flag = false; } else { flag = manger.popView(layer); } } else { for (let index = this.managers.length - 1; index >= 0; index--) { const manager = this.managers[index]; if (manager.canPop() && manager.count() > 0) { if (manager.popView(null)) { flag = true; break; } } } } return flag; } //得到當前存在的ui的數量 getOpenUICount() { let count: number = 0; for (let index = this.managers.length - 1; index >= 0; index--) { const manager = this.managers[index]; if (manager.canPop()) { count += manager.count() } } return count; } }
import LayerInterface from "../cfw/ui/LayerInterface"; import { UIIndex } from "../cfw/tools/Define"; const { ccclass, property } = cc._decorator; @ccclass export default class EngineView extends cc.Component implements LayerInterface { private uiIndex: number = 0; protected loadFlag: boolean = false; isLoad() { return this.loadFlag } start() { this.loadFlag = true; } exit() { this.node.destroy() } setVisible(f: boolean): void { this.node.active = f; } setOrder(order: number): void { this.node.zIndex = order; } setUIIndex(t: UIIndex): void { this.uiIndex = t; } getUIIndex(): UIIndex { return this.uiIndex } getNode() { return this.node; } show() { UIManager.instance().pushView(this) } hide(){ UIManager.instance().popView(this) } }
//ui分層 export enum UIIndex { ROOT,//最底層 STACK,//堆棧管理 QUEUE,//隊列管理 TOAST,// TOP,//永遠不會清除的ui層 }
初始化:
this
封裝函數:spa
/** * 將ui添加到管理器中。 * @param prefab 預製體麓景 * @param className 組件類型 * @param model 模型 * @param uiIndex ui管理器層級 * @param loader 加載器 * @param func 加載成功回調 */ pushView(prefab: string, className: string, c: BaseController, model: any, uiIndex: UIIndex = UIIndex.STACK, loader: ResLoader, func?: Function) { if (this.viewMap.has(prefab)) { console.warn(' pushVIew ', this.viewMap.has(prefab)) return; } this.viewMap.set(prefab, 1) this.pushToast(prefab, className, c, model, uiIndex, loader, (comp) => { // console.log(' delete viewMap ', prefab) this.viewMap.delete(prefab) if (func) { func(comp) } }) } /** * * @param prefabName 預製體的名稱 * @param callback 加載後的回調。 */ getPrefab(prefabName: string, loader: ResLoader, callback: (err: string, node?: cc.Node) => void) { let resName = ""; if (prefabName.indexOf("/") >= 0) { resName = prefabName; let list = prefabName.split("/"); prefabName = list[list.length - 1]; } else { resName = "prefabs/" + prefabName; } loader.loadRes(resName, ResType.Prefab, (err, item: ResItem) => { if (err) { callback(" UIManager getComponent err " + err); return; } //這裏能夠配合對象池使用。 let node = cc.instantiate(item.getRes()) if (node) { callback(null, node); } else { callback("node is null"); } }); }
這裏邊有個一小的處理,就是當一個UI成功加載後纔會彈出另外一個UI,避免的按鈕被連續點擊彈出多個UI的狀況。
使用:3d
this.pushView('LoginView', 'LoginView', null, ModuleManager.getLoader(), UIIndex.ROOT)
歡迎掃碼關注公衆號《微笑遊戲》,瀏覽更多內容。
歡迎掃碼關注公衆號《微笑遊戲》,瀏覽更多內容。