本篇我们来创建FGUI的窗口管理类
FGUI文档中有关于窗口系统的描述【FGUI文档——窗口系统】
按照文档中的说法
我们在创建一个高层级的组件的时候
不应该直接将组件放在GRoot下(FGUI的根节点)
而是应该先创建窗口再放置这些组件
首先我们创建一个UI管理器,并为他添加以下方法
public static async ShowWnd(pkg: string,name: string) {
//异步加载FGUI包资源
await $promise(API.LoadFairyGUIPackage(pkg));
//创建窗口
let win: FairyGUI.Window = new FairyGUI.Window();
//创建窗口内容
win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;
//全屏显示
win.MakeFullScreen();
//显示窗口
win.Show();
}
使用上面的方法我们就可以创建一个窗口并将组件作为窗口中的内容放在窗口中显示
这样我们通过窗口的API可以更容易的控制界面
我们可以使用FGUI的窗口可以作为基类,进行拓展
export interface IGwndController extends IController {
//窗口的拓展接口
}
export abstract class AbstractGWndController extends FairyGUI.Window implements IGwndController{
//窗口的拓展实现
}
这样我们就拓展好了FGUI的窗口
在游戏中,我希望每个窗口都有自己的类
而上面的抽象类只作为一个模板存在
export class WndLogin extends AbstractGWndController{
//具体窗口的实现
}
这样我们就拥有了实际窗口类,他们与FGUI编辑器中我们所设计的界面一一对应
所以我们需要将他们的对于关系存储起来
先思考一个我们需要一个什么样的结构
这样我们就先定义了一个接口类型
export interface IUIInfo {
pkgName: string
itemId: string
script: any
windName: string
}
然后我们建了一个类专门用于管理窗口信息与组件拓展信息
export class UITable {
public static UIWindow = {
WndGameMain: { pkgName: "GameMain", itemId: "WndGameMain", script: WndGameMain, windName: "WndGameMain" },
WndLogin: { pkgName: "Login", itemId: "WndLogin", script: WndLogin, windName: "WndLogin" },
}
}
这样我们在需要创建窗口的时候只需要填入窗口名,就可以把窗口创建出来了,修改以下窗口创建函数
public static async ShowWnd(windName: string) {
let info: IUIInfo = UITable.UIWindow[windName]
//判断是否存在窗口信息
if (info != null) {
let pkg = info.pkgName
let name = info.itemId
let scr = info.script
let wndName = info.windName
//异步加载FGUI包资源
await $promise(API.LoadFairyGUIPackage(pkg))
//创建窗口
let win: AbstractGWndController = new scr();
win.name = wndName;
//创建窗口内容
win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;
win.MakeFullScreen();
//绑定子组件(这个方法自行拓展)
win.BindChild(win);
FairyGUI.GRoot.inst.ShowWindow(win);
}
else {
TSLog.Error("WindowName:【" + windName + "】 does not exist or is misspelled,Please check the spelling");
}
}
这样我们就可以通过我们自己的UI管理器创建出一个我们自己拓展的窗口了
接下来我们来做弹出窗口即点击空白区域会自动关闭的窗口
首先,不要总想着自己一个人造车,先翻一下FGUI文档吧
于是我在FGUI的文档中找到了【FGUI文档——Popup】的内容
按照文档中的描述,十分的简单
显示普通窗口我们用的是
窗口类中Show()的方法
而显示弹出窗口我们只需要把需要这个效果的窗口作为参数传入
FairyGUI.GRoot.inst.ShowPopup()这个方法就可以了
由于创建窗口的部分与普通窗口时公用的,所以我将它分离出来
//有窗口返回窗口,无窗口创建窗口
private async GetWnd(windName: string): Promise<AbstractGWndController> {
let info: IUIInfo = UITable.UIWindow[windName]
if (info == null) {
TSLog.Error("WindowName:【" + windName + "】 does not exist or is misspelled,Please check the spelling");
return null;
}
try {
if (this.HasWnd(windName)) {
return this.Map_WndInstance.get(windName);
}
else {
let pkg = info.pkgName
let name = info.itemId
let scr = info.script
let wndName = info.windName
//异步加载FGUI包资源
await $promise(API.LoadFairyGUIPackage(pkg))
//创建窗口
let win: AbstractGWndController = new scr();
win.name = wndName;
//创建窗口内容
win.contentPane = FairyGUI.UIPackage.CreateObject(pkg, name).asCom;
win.MakeFullScreen();
//绑定代码
win.fui = win.contentPane;
win.BindAll(win);
//存储窗口对象
this.Map_WndInstance.set(windName, win);
return win;
}
}
catch {
TSLog.Error("WindowName:【" + windName + "】 throw error when create");
}
return null;
}
将显示普通窗口的方法修改一下
public async ShowWnd(windName: string, modal: boolean = true) {
let wnd: AbstractGWndController = await this.GetWnd(windName);
if (wnd == null) {
TSLog.Error("WindowName:【" + windName + "】 can not get this window");
}
wnd.modal = modal;
FairyGUI.GRoot.inst.ShowWindow(wnd);
}
然后接下来只需要写一个弹出窗口的方法就可以了
public async ShowPopWnd(windName: string, modal: boolean = true) {
let wnd: AbstractGWndController = await this.GetWnd(windName);
if (wnd == null) {
TSLog.Error("WindowName:【" + windName + "】 can not get this window");
}
LinxLog.Log("PopWnd")
wnd.modal = modal;
FairyGUI.GRoot.inst.ShowPopup(wnd);
}
似乎这样就可以了
然而在测试的时候我发现好像并不能点击空白处关闭窗口
我的组件时这样的

研究了一下发现,我需要把组件属性中的点击穿透开起来才可以

而在这过程中,我还发现了FGUI为我们做好了黑遮的效果
只需要在窗口中将modal这个属性设为true就可以了
这个功能一样要把组件中的点击穿透开启才会生效
这样才一个窗口内的空白区域,会被modal遮挡,阻止穿透到其他的窗口
按照上述方式来创建显示窗口
我们会使用一个Map来存储已经存在的窗口
public Map_WndInstance: Map<string, AbstractGWndController> = new Map<string, AbstractGWndController>();
这样我们做隐藏和销毁就很容易了
//隐藏窗口
public HideWnd(windName: string) {
if (this.HasWnd(windName)) {
let wnd = this.Map_WndInstance.get(windName);
FairyGUI.GRoot.inst.HideWindow(wnd);
}
}
//隐藏弹窗
public HidePopWnd(windName: string) {
if (this.HasWnd(windName)) {
let wnd = this.Map_WndInstance.get(windName);
FairyGUI.GRoot.inst.HidePopup(wnd);
}
}
//销毁窗口
public DisposeWnd(windName: string) {
if (this.HasWnd(windName)) {
let wnd = this.Map_WndInstance.get(windName);
wnd.Dispose();
this.Map_WndInstance.delete(windName);
}
}