1. 程式人生 > 其它 >laya fgui 超簡單的UI框架

laya fgui 超簡單的UI框架

FairyGUI 超簡單的UI框架

Laya使用fgui的超簡單UI框架

使用場景:用於使用fgui進行layaUI開發的程式人員

整個框架分為3個模組,共有4個類:

  • FGUIManager :FGUI的管理類,繼承於IUIManager 負責所有UI的開啟關閉等事項
  • FUIBase :UI的管理基類,具體實現
  • IUIManager :FGUI的介面類 規定管理類的各個方法
  • UILayerType: UI 層級分類
FGUIManager管理類
    import IUIManager from "./IUIManager";
    import { FUIBase } from "./FUIBase";
    import GameEntry from "../../GameEntry";

    /**
    * @ name:FGUIManager
    * @ desc:自動建立說明
    * @ user:By NUOLO
    * @ data: 2021-06-02 18:14
    */
    export default class FGUIManager implements IUIManager {
    /**
    *
    */
    constructor() {
        this.Init();
    }

    Init(): void {
        Laya.stage.addChild(fgui.GRoot.inst.displayObject);		//初始化FGUI
        this.UIroot = fgui.GRoot.inst.displayObject;
        this.UIroot.width = Laya.stage.width;
        this.UIroot.height = Laya.stage.height;
        fgui.UIConfig.packageFileExtension = "fui";			//設定匯出檔案的拓展名  程式碼預設的拓展名為fui,可能於自身匯出的拓展名不同 但最好這樣做因為有些平臺只認這種檔名
        this.UIDic = {};
    }

        /**
        * UI字典
        */
        UIDic: { [name: string]: FUIBase<fgui.GComponent>};
        
        /**
        * UI的根節點
        */
        private UIroot: Laya.Sprite;
        /**
        * 注入FUIBase 
        */
        RigisterUIBase(name: string, ui: FUIBase<fgui.GComponent>): void {
            if (this.UIDic[name]) {
                console.log(name + "::欄位已存在UI介面,請勿重複新增")
                return;
            }
            else {
                this.UIDic[name] = ui;
            }
        }

        CreateOrOpenPanel(name: string, data?:new () => FUIBase<fgui.GComponent> , isCloseOther?: boolean): FUIBase<any> {
        if (!this.UIroot) {
                this.Init();
            }
            if (this.UIDic[name]) {
            return this.OpenPanel(name, isCloseOther);
            }
            else {
                let cla = new data();

                if (fgui.UIPackage.addPackage(data['ResName']) == null) {
                    console.log('資源包未載入,將進行自動載入');
                    fgui.UIPackage.addPackage(data['ResName']);
                }

                // let com = fgui.UIPackage.createObject(data['UIpackName'], data['UIName'], cla.ClassType).asCom;
                let com =  fgui.UIPackage.createObjectFromURL(cla.ClassType.URL,cla.ClassType).asCom ;
                com.name = data['UIName'];
                fgui.GRoot.inst.addChild(com);
                com.makeFullScreen();

                com.sortingOrder = cla.LayerType;
                cla.MUI = com;
                cla.UIMgr = this;
                cla.AutoRigisterToUIManager();
                cla.onAwake();
                cla.onEnable();
                return cla;
            }
        }

        OpenPanel(name: string, isCloseOther?: boolean): FUIBase<any> {
            if (isCloseOther) {
                for (let uiname in this.UIDic) {
                    this.UIDic[uiname].Close();
                }
            }
            if (this.UIDic[name]) {
                let ui = this.UIDic[name];
                ui.Open();
                return ui;
            }
            else {
        
                console.error(name + "::欄位在UI字典中不存在,請檢查是否有誤")
                return null;
            }
        }
        ClosePanel(name: string, toOpenWindow?: string): void {
            if (this.UIDic[name]) {
                let ui = this.UIDic[name];
                ui.Close();
                if (toOpenWindow != null) {
                    this.OpenPanel(toOpenWindow);
                }
            }
            else {
                console.log(name + "::欄位在UI字典中不存在,請檢查是否有誤")
            }
        }
        CloseAllPanel(): void {
            for (const key in this.UIDic) {
                this.UIDic[key].Close();
            }
        }
        GetUIPanel(name: string): any {
            if (this.UIDic[name]) {
                return this.UIDic[name] ;
            }
            else {
                console.log(name + "::欄位在Ui字典中不存在,請檢查")
                return null;
            }
        }
        DestoryUIPanel(name: string) {
            if (this.UIDic[name]) {
                this.UIDic[name].Destory();
            }
            else {
                console.log(name + "::欄位在Ui字典中不存在,請檢查")
            }
        }

        
    }
FUIBase
    import AssetData from "../../Asset/AssetData";
    import Debug from "../../Debug/Debug";
    import GameEntry from "../../GameEntry";
    import IUIManager from "./IUIManager";
    import { UILayerType } from "./UILayerType";

    /**
    * @ name:FUIBase
    * @ desc:自動建立說明
    * @ user:By NUOLO
    * @ data: 2021-06-02 16:24
    */
    export class FUIBase<T extends fgui.GComponent>  {

        /**需子類設定 匯出包的路徑 */
        public static ResName: string = "res/UIVSLoading";
        /**需子類設定 圖集的數量 從0 開始 */
        public static AtliasCount: number = 1;

        public static UIName: string = "1";                     //UI的名字 要存在字典中
        public get UIName(): string { return FUIBase.UIName; }
        public set UIName(v: string) { FUIBase.UIName = v; }

        /** UI的層級  預設0級為最底層 */
        public LayerType: UILayerType = UILayerType.Normal;

        /**fgui 元件 */
        private m_uiComPonent: T;
        public get MUI(): T { return this.m_uiComPonent; }
        public set MUI(v: T) { this.m_uiComPonent = v;  }

        /**fgui 元件 */
        public ClassType: any;
 
        /**UI管理類 */
        private m_uimgr: IUIManager;
        public get UIMgr(): IUIManager { return this.m_uimgr; }
        public set UIMgr(v: IUIManager) { this.m_uimgr = v; }

        /**
        * 自動註冊進UIManager
        */
        public AutoRigisterToUIManager() {
            this.UIMgr.RigisterUIBase(this.UIName, this);
        }


        /**
        * 開啟介面
        */
        public Open() {
            this.onEnable();
            this.m_uiComPonent.visible = true;

        }
        /**
    * 關閉介面
    */
        public Close() {
            this.onDisable();
            this.m_uiComPonent.visible = false;
        }

        /**
        * 銷燬介面
        */
        public Destory() {
            this.m_uiComPonent.dispose();
        }

        //#region fgui載入

        /**
        * 獲取當前介面所對應的資原始檔
        * @returns 
        */
        public static GetLoadUIPackDic(): any[] {
            let urls = [];
            urls.push({ url: this.ResName + ".fui", type: Laya.Loader.BUFFER });
            urls.push({ url: this.ResName + "_atlas0.png", type: Laya.Loader.IMAGE });
            //載入紋理集
            if (this.AtliasCount >=1) {
                for (let i = 1; i <= this.AtliasCount; i++) {
                    urls.push({ url: this.ResName + "_atlas0_" + i + ".png", type: Laya.Loader.IMAGE });
                }
            }
            return urls;
        }

        /**
        * 獲取FGUI 二進位制檔案路徑
        * @returns 對應路徑
        */
        public static GetUIByte(): string {
            return this.ResName + ".fui";
        }
        /**
        * 載入完成之後 將包新增到fgui包管理中
        */
        public static AddPackage() {
            fgui.UIPackage.addPackage(this.ResName);
        }
        //#endregion


        //#region  功能

        /**
        *  獲得子節點
        * @param path 路徑資訊  s.b.v
        */
        public FindChild<T extends fgui.GObject>(path: String): T {
            return this.m_uiComPonent.getChildByPath(path) as T;
        }

        /**
        * 新增事件監聽
        * @param btn 點選按鈕
        * @param callback 回撥
        * @param args 傳遞資料
        */
        public AddLinster(btn: fgui.GObject, callback, ...args) {
            btn.onClick(this, callback, args);
        }

        /**
        * 移除事件監聽
        * @param btn 按鈕
        * @param callback 回撥
        */
        public RemoveLinster(btn: fgui.GObject, callback) {
            btn.offClick(btn, callback);
        }
        //#endregion


        //#region 生命流程

        onAwake() {}        //onAwake 建立時呼叫
        onEnable() {}       //每次開啟時呼叫,可自行拓展開啟時的開啟效果等功能
        onDisable() {}      //每次關閉時呼叫,可自行拓展關閉時的 所需呼叫的功能
        //#endregion
    }
IUIManager
    import { FUIBase } from "./FUIBase";

    /**
    * @ name:IUIManager
    * @ desc:UI管理類的介面
    * @ user:By NUOLO
    * @ data: 2021-06-02 16:14
    */
    export default interface IUIManager {
        
        /**
        * 初始化
        */
        Init():void

        /**
        * UI字典
        */
        UIDic: { [name: string]: FUIBase<any> };

        /**
        * 注入FUIBase 
        */
        RigisterUIBase(name: string, ui: FUIBase<any>): void;
        
        /**
        * 自動建立 或者開啟 介面 注意:建立UI是非同步操作的
        * @param name 名字
        * @param isCloseOther 是否關閉其他介面
        * @param data 資料
        */
        CreateOrOpenPanel(name: string, data?:any, isCloseOther?: boolean ): FUIBase<any>

        /**
        * 開啟UI介面
        * @param name 要開啟介面的名字
        * @param isCloseOther 是否關閉其他介面 預設否
        */
        OpenPanel(name: string, isCloseOther?: boolean): FUIBase<any>;

        /**
        * 關閉UI介面 
        * @param name 要關閉UI介面的名字
        * @param TOOpen 關閉此介面後要開啟的介面的名字  預設無  不開啟其他介面
        */
        ClosePanel(name: string,toOpenWindow?:string): void;
        /**
        * 關閉所有UI介面
        */
        CloseAllPanel(): void;
        /**
        * 根據識別符號獲取FUIBase
        * @param name 識別符號
        */
        GetUIPanel(name: string):any;

        /**
        * 銷燬UIPanel
        * @param name 識別符號
        */
        DestoryUIPanel(name: string);

    }
UILayerType
    /**
    * @ name:UILayerType
    * @ desc:UI 層級分類
    * @ user:By NUOLO
    * @ data: 2021-06-02 16:55
    */
    export  enum UILayerType {
    //普通窗體
    Normal=0,
    //固定窗體
    Fixed=20,
    //彈出窗體
    PopUp = 50,
    //提示窗體
    Tip = 40,
    }

框架就分為這4個類 使用的話就每個UI介面都繼承 FUIBase<具體fgui匯出的UI類>
並重寫 引數

如例子:

fgui 匯出檔案為  Package1.fui
                Package1Binder.ts
                UI_Component1.ts
                Package1Binder.ts

新建一個ShowUI 的指令碼 繼承與FUIBase <UI_Component1>
示例 ShowUI類
    import { FUIBase } from "../Core/UI/FGUI/FUIBase";
    import { UILayerType } from "../Core/UI/FGUI/UILayerType";
    import Package1Binder from "./Package1/Package1Binder";
    import UI_Component1 from "./Package1/UI_Component1";


    /**
    * @ name:ShowUI
    * @ desc:UI的控制類 
    * @ user:By NUOLO
    * @ data: 2021-06-09 11:00
    */
    export default class ShowUI extends FUIBase <UI_Component1>{


        public static ResName: string = "res/FGUI/Package1";    //路徑
        public static AtliasCount: number = 0;                  //圖集數量 從0開始
        public static UIName: string = "1";                     //名稱
        constructor() {
            super();
            this.LayerType = UILayerType.Normal;                //設定層級
            this.ClassType = UI_Component1;                     //設定UI所對應的類,,確定好再填
            Package1Binder.bindAll();                           //UI繫結類
        }

        
        onAwake() {
            super.onAwake();
        }
        onEnable() {
            super.onEnable();
        }
        onDisable() {
            super.onDisable();
        }
    }
示例 呼叫方法
    onConfigLoaded(): void {
        //載入IDE指定的場景
        //  GameConfig.startScene && Laya.Scene.open(GameConfig.startScene);
        this.openFGUI();
    }
    openFGUI() {
        let uimagr = new FGUIManager();			//初始化UI管理類

        //開啟介面
        Laya.loader.create(ShowUI.GetLoadUIPackDic(), Laya.Handler.create(this, () => {
            uimagr.CreateOrOpenPanel(ShowUI.UIName, ShowUI);
        }));
    }

整個呼叫過程都很簡單,程式碼邏輯也很明瞭,自己正在使用中
如果有更好的方法和更優雅的寫法,也請通過郵件聯絡我,共同學習一下,多謝!

個人部落格地址 https://nuolo.xyz