一只腊鸭做游戏

决战-Pow!第二集:UI管理

2018-02-03  本文已影响11人  回忆并快

有了基本的模块化管理,接下来另外很重要的就是UI管理。
一个方便易用的UI框架,会大大提高我们开发界面逻辑效率。

今天来为大家带来一个我实现的UI管理(基于Layabox)

首先,LayaIDE里面已经包含了一个比较强大的UI编辑器。


Login界面

这里为了做UI的适配,可以添加了一个根节点root(宽高为iphone7的分辨率(这个分辨率我会动态变更),锚点anchor在中心)
然后根据相应UI需要进行何种对齐来进行设置内部节点,如下图。


绝对居中的部分,且向上偏移32个像素,这里只需要设置centerX和centerY属性
然后如果我想让某部分UI始终,左下对齐,可以这么编辑UI。 设置宽高同root(方便对位置),然后设置left和bottom属性为0,并且设置锚点为0,1

这些是我对UI的约定,为了程序中做适配。
然后导出并且发布资源,UI资源准备就基本完成了~

编写基本UI逻辑,其实就是创建一个自己管理的类来继承Laya的View。

class LoginPage extends ui.LoginPageUI{
    constructor(){
        super();
        this.initialize();
    }
    initialize(){
        this.startButton.on(Laya.Event.CLICK, this, this.onStart);
    }
    onStart(){
        PluginManager.getInstance().openPlugin(PluginType.LOBBY);
    }
}

像这个登录界面,逻辑就很简单,直接初始化后,监听startButton的点击事件,用来触发打开大厅插件。
当然除了这个还有一些对话框的需求,这里采用Laya的Dialog来解决,同样是继承一个类不过继承的是Dialog。
像这个房间列表(暂时用假数据代替内容)


房间列表,这个UI的大小即为模态层点击的区域,跟前面的界面编辑不太一样
class RoomDialog extends ui.RoomDialogUI{
    private _roomList:Array<any> = [{name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}, {name: "test"}]
    constructor(){
        super();

        this.roomList.array = this._roomList;
        this.roomList.vScrollBarSkin = "";
        this.roomList.renderHandler = Handler.create(this, this.onRenderHandler);
        this.roomList.mouseHandler = Handler.create(this, this.onMouseHandler);
        this.roomList.refresh();
        this.roomList.scrollBar.elasticBackTime = 150;
        this.roomList.scrollBar.elasticDistance = 200;
    }
    onRenderHandler(cell:Laya.Box,index:number){
        Logger.log("onRenderHandler");
    }
    onMouseHandler(cell:Laya.Event,index:number){
        Logger.log("onMouseHandler");
        
    }
}

然后这个UI通过什么来管理呢,我创建了一个UIManager来管理,这个类包含了界面打开,关闭,适配等等逻辑,还有对话框的管理。

class UIManager{
    private static _instance: UIManager = null;
    constructor() {}
    public static getInstance(): UIManager {
        return this._instance || (this._instance = new this());
    }
    
    initialize(){
    }

    closePage(classObj:any){
        if(this._pages.containsKeyValue(classObj)){
            this._pages.get(classObj).removeSelf();
            this._pages.get(classObj).destroy();
            this._pages.set(classObj, null);
            this._pages.removeKeyValue(classObj);
        }
    }

    closeAllPages(){
        for(let pair of this._pages){
            if(pair.value != null){
                pair.value.removeSelf();
                pair.value.destroy();
                this._pages.set(pair.key, null);
            }
        }
    }

    closeAllDialogs(){
        for(let pair of this._dialogs){
            if(pair.value != null){
                pair.value.close();
                pair.value.destroy();
                this._dialogs.set(pair.key, null);
            }
        }
    }

    private _dialogs:Dictionary<any, any> = new Dictionary<any, any>();

    closeDialog(classObj:any){
        if(this._dialogs.containsKeyValue(classObj)){
            if ((this._dialogs.get(classObj) as Laya.Dialog).parent != null){
                (this._dialogs.get(classObj) as Laya.Dialog).close();
                // this._dialogs.get(classObj).destroy();
                // this._dialogs.set(classObj, null);
            }
            this._dialogs.removeKeyValue(classObj);
        }
    }

    openDialog(classObj:any, data?:any, closeAll?:boolean){
        let dialog:Laya.Dialog = new classObj(data) as Laya.Dialog;
        dialog.closeEffect = null;
        if(!dialog) {
            Logger.log("dialog dont exist.");
            return null;
        }
        if(closeAll){
            this.closeAllDialogs();
        }
        if(this._dialogs.containsKeyValue(classObj)){
            Logger.log("dialog exist.");
            dialog.popup();
            return dialog;
        }
        dialog.popup();
        // dialog.closeHandler = Handler.create(this, function(name){
        //     UIManager.getInstance().closeDialog(classObj);
        // })
        this._dialogs.addKeyValue(classObj, dialog);
        return dialog;
    }

    getDialog(clsObj:any){
        return this._dialogs.get(clsObj);
    }

    private _pages:Dictionary<any, any> = new Dictionary<any, any>();

    getPage(clsObj:any){
        return this._pages.get(clsObj);
    }

    openPage(classObj:any, clossAll?:boolean, parent?:Laya.Node):any{
        let page:any = new classObj();
        if(!page) {
            Logger.log("page dont exist.");
            return null;
        }
        if(clossAll){
            this.closeAllPages();
        }
        if(this._pages.containsKeyValue(classObj)){
            return this._pages.get(classObj);
        }
        if (parent) {
            parent.addChild(page);
        }else{
            Laya.stage.addChild(page);
        }
        // 这里是约定逻辑,会同台调整root的大小,以至于适配
        if(page["root"] != null){
            let ratio = Laya.Browser.width/Laya.stage.width;
            let oy:number = ((Laya.stage.height*ratio - Laya.Browser.height)/ratio);
            page["root"].size(750, 1334-oy);
        }
        this._pages.addKeyValue(classObj, page);
        return page;
    }
}

这里需要额外注意一下root的处理。
对于一些常用UI例如Loading之类,我直接实用一个UICommon管理:

class UICommon{
    private static _loadingPage:BackgroundPage
    static createUI(){
        if(this._loadingPage == null){
            this._loadingPage = new BackgroundPage();
        }
    }
    public static openLoading(){
        this.createUI();
        if(this._loadingPage.parent == null){
            Laya.stage.addChild(this._loadingPage);
        }
        this._loadingPage.showLoading();
    }
    public static closeLoading(){
        if(this._loadingPage == null) return;
        if(this._loadingPage.parent){
            this._loadingPage.setLoading('');
            this._loadingPage.hideLoading();
            this._loadingPage.removeSelf();
        }
    }
    public static setLoadingText(progress:number){
        if(this._loadingPage == null) return;
        if(this._loadingPage.parent){
            this._loadingPage.setLoading("当前进度:" + progress + "%");
        }
    }
    public static showBackground(){
        this.createUI();
        if(!this._loadingPage.parent){
            Laya.stage.addChild(this._loadingPage);
        }
        this._loadingPage.hideLoading();
    }
}

这些都准备好了,我应该如何使用?
打开Loading我可以这样:

UICommon.openLoading();

打开普通界面:

// 登录界面
let page:LoginPage = UIManager.getInstance().openPage(LoginPage);
page.pow.play(); // 播放登录动画

打开对话框(模态层):

// 房间列表对话框
UIConfig.popupBgAlpha = 0.75;
let roomDialog:Laya.Dialog = UIManager.getInstance().openDialog(RoomDialog);
roomDialog.closeHandler = Handler.create(this, ()=>{
    this.close();
});

这样满足了我们在游戏中最基本的UI需求,当然还有更加复杂的UI功能就需要对这些内容进行扩展。

终于写完了第二集,因为年会的原因,拖延了更新,后面会好好做调整,做到两天一更。

上一篇 下一篇

猜你喜欢

热点阅读