cocos2d-js 实现窗体管理器

该窗体管理器拥有四个接口:

1.弹出自带左上角返回的全屏界面

WinMgrGetInstance().addBackLayer(layer, exitFunc);

exitFunc 表示关闭时调用的exitFunc,比如刷新操作等
~弹出全屏界面后会隐藏之前弹出的所有界面,无需手动隐藏

2.弹出自带关闭按钮的非全屏界面

WinMgrGetInstance().addPopLayer(layer, exitFunc, {maskShadow: false, maskClose: true, showSingle: false, hideBefore: true});

exitFunc 表示关闭时调用的exitFunc
maskShadow 表示背景mask是否灰态
maskClose 表示点击mask是否关闭当前界面,mask能不能点击到和json也有关
showSingle 表示弹出后是否关闭前一个非全屏界面
hideBefore 表示弹出后是否隐藏前一个非全屏界面
~自带mask,不需要在界面中手动增加mask,避免太暗
~统一移除接口,不要自己通过remove移除当前界面,点击叉叉按钮调用关闭最上层界面进行移除

3.关闭最上层的界面

WinMgrGetInstance().cleanTopLayer();

~会自动显示被隐藏的下一层界面,无须担心

4.关闭所有已打开界面

WinMgrGetInstance().cleanAllLayer();

~切场景的时候要调
~功能跳转操作要调,然后打开新功能

实现代码如下:

WindowManager = cc.Node.extend({

    TYPE_BACK       : 1,
    TYPE_POP        : 2,

    UI_ZORDER_BASE  : 1000,

    UI_TAG_BACK     : 100,
    UI_TAG_MASK     : 200,
    UI_TAG_BASE     : 1000,

    _layerlist : [],

    ctor: function () {
        this._super();
        this.initLayer();
        this.initBackBtn();
        this.initMaskLayer();
    },

    onEnter:function () {
        this._super();
    },

    onExit: function() {
        this._super();
    },

    initLayer: function() {
        this._baseLayer = new cc.Layer();
        g_director.getRunningScene().addChild(this._baseLayer, 1000, 9527);
    },

    initBackBtn: function() {
        this._backLayer = op.ResourceManager.getInstance().LoadUIWidget("BackButtonUi_1.json");
        this._backLayer.setAnchorPoint(cc.p(0.5,0.5));
        this._backLayer.setPosition(g_winCenter);
        this._backLayer.setSize(g_winSize);
        this._backLayer.setVisible(false);
        this._baseLayer.addChild(this._backLayer, this.UI_ZORDER_BASE, this.UI_TAG_BACK);

        this._back_btn = this._backLayer.getChildByName("Panel_Back").getChildByName("back");
        this._back_btn.addTouchEventListener(LayoutConfig.addTouchEventListener(this.cleanTopLayer, this), this);

        var safeArea = LayoutConfig.GetSafeArea();
        var back_pos = cc.p(this._back_btn.getPosition().x + safeArea.x, this._back_btn.getPosition().y);

        this._back_btn.setPosition(cc.p(back_pos.x-this._back_btn.getContentSize().width, back_pos.y));
        this._back_btn.runAction(cc.Sequence.create(
            cc.Spawn.create(
                cc.MoveTo.create(0.15,cc.p(back_pos.x+this._back_btn.getContentSize().width/3, back_pos.y)),
                cc.FadeIn.create(0.15)),
            cc.MoveTo.create(0.05, back_pos))
        );
    },

    initMaskLayer: function() {
        this._maskLayer = LayoutConfig.attachMask(this._baseLayer, 0, this.UI_TAG_MASK, true);
        this._maskLayer.setVisible(false);
    },

    addBackLayer: function(layer, exitFunc) {
        var index = this._layerlist.length + 1;
        if (layer) {
            var self = this;
            var newExitFunc = function() {
                if (layer) {
                    if (exitFunc) {
                        exitFunc.call(layer);
                    }
                    layer.removeFromParent();
                    layer = null;
                    self._layerlist.pop();
                    self.refreshTopLayer();
                }
            }

            // 隐藏之前所有窗体
            if (this._layerlist.length > 0) {
                for (var i = 0; i < this._layerlist.length; i++) {
                    if (this._layerlist[i].visible) {
                        this._layerlist[i].layer.setVisible(false);
                        this._layerlist[i].visible = false;
                    }
                }
            }

            this._baseLayer.addChild(layer, index*this.UI_ZORDER_BASE, index*this.UI_TAG_BASE);
            this._layerlist.push({index: index, type: this.TYPE_BACK, layer: layer, exitFunc: newExitFunc, visible: true});
            this.refreshTopLayer();
        }
    },

    addPopLayer: function(layer, exitFunc, optional = {}) {
        var index = this._layerlist.length + 1;
        if (layer) {
            var self = this;
            var newExitFunc = function() {
                if (layer) {
                    if (exitFunc) {
                        exitFunc.call(layer);
                    }
                    layer.removeFromParent();
                    layer = null;
                    self._layerlist.pop();
                    self.refreshTopLayer();
                }
            }

            // 清除或隐藏前一个弹窗窗体
            if (optional.showSingle || optional.hideBefore) {
                var layerNum = this._layerlist.length;
                if (layerNum > 0) {
                    var topData = this._layerlist[layerNum-1];
                    if (topData.type == this.TYPE_POP) {
                        if (optional.showSingle) {
                            this.cleanTopLayer();
                        } else {
                            this._layerlist[layerNum-1].layer.setVisible(false);
                            this._layerlist[layerNum-1].visible = false;
                        }
                    }
                }
            }

            this._baseLayer.addChild(layer, index*this.UI_ZORDER_BASE, index*this.UI_TAG_BASE);
            this._layerlist.push({index: index, type: this.TYPE_POP, layer: layer, exitFunc: newExitFunc, visible: true, maskShadow: optional.maskShadow, maskClose: optional.maskClose});
            this.refreshTopLayer();
        }
    },

    refreshTopLayer: function() {
        var layerNum = this._layerlist.length;
        if (layerNum > 0) {
            this._layerlist[layerNum-1].visible = true;
            var topData = this._layerlist[layerNum-1];
            topData.layer.setVisible(true);

            if (topData.type == this.TYPE_BACK) {
                this._backLayer.setVisible(true);
                this._backLayer.setLocalZOrder(topData.index*this.UI_ZORDER_BASE+10);
            } else {
                // 找出最上层的TYPE_BACK,重置返回按钮zorder
                this._backLayer.setVisible(false);
                for (var i = layerNum-1; i >= 0; i--) {
                    if (this._layerlist[i].type == this.TYPE_BACK) {
                        this._layerlist[i].layer.setVisible(true);
                        this._layerlist[i].visible = true;
                        this._backLayer.setVisible(true);
                        this._backLayer.setLocalZOrder(this._layerlist[i].index*this.UI_ZORDER_BASE+10);
                        break;
                    }
                }
            }

            this._maskLayer.setVisible(true);
            this._maskLayer.setLocalZOrder(topData.index*this.UI_ZORDER_BASE-10);
            this._maskLayer.setBackGroundColorOpacity(topData.maskShadow ? 180 : 0);

            if (topData.maskClose) {
                this._maskLayer.addTouchEventListener(LayoutConfig.addTouchEventListenerNoAnima(topData.exitFunc, topData.layer), this);
            } else {
                this._maskLayer.addTouchEventListener(function() {}, this);
            }
        } else {
            this._backLayer.setVisible(false);
            this._maskLayer.setVisible(false);
        }
    },

    cleanTopLayer: function() {
        var layerNum = this._layerlist.length;
        if (layerNum > 0) {
            var topData = this._layerlist[layerNum-1];
            if (topData.layer) {
                topData.exitFunc.call(topData.layer);
            } else {
                this._layerlist.pop();
                this.refreshTopLayer();
            }
        }
    },

    cleanAllLayer: function() {
        if (this._layerlist.length > 0) {
            this.cleanTopLayer();
            this.cleanAllLayer();
        }
    },

});

var g_WindowMgr = null;
var WinMgrGetInstance = function() {
    if(!g_WindowMgr){
        g_WindowMgr = new WindowManager();
        g_WindowMgr.retain();
    }
    return g_WindowMgr;
};

未完待续:
~需要增加弹出信息框界面并管理
~目前四个接口只在MainScene(主城)上调用才有效,后续进行优化
~根据BaseNode中的_event_tag前缀判断当前打开界面,脚本报错将界面列表上传bugly,增加错误重现概率

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值