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