cocos creator从零开发简单框架(11)-顶层遮挡

有这样一个场景,当点击了某个按钮,但它可能要跟后端交互并且会花费一定时间,这个时候不能再次点击按钮。要实现这个功能,一般是添加一个标志位,当点击后设为一个状态,当处理完逻辑后设为初始状态。这个实现如果项目多处用到就比较麻烦,换一种方式,直接在顶层添加一个Block Input Events组件就行。

新建framework/scripts/view/TopBlock.ts,内容如下。主要就是生成一个节点,把它挂载在Top层级并铺满屏幕,调用show方法时,显示这个节点拦截所有点击事件,调用hide方法隐藏这个节点。

import AppConstants from "../AppConstants"
import AppUtil from "../AppUtil"
import LayerMgr from "./LayerMgr"


export default class TopBlock {
    private static _view: cc.Node


    public static show() {
        this.ensure()

        LayerMgr.setLayer(this._view, AppConstants.viewLayer.Top)
        this._view.active = true
    }

    public static hide() {
        if (!this._view || !this._view.isValid) return

        this._view.active = false
    }


    private static ensure() {
        if (this._view && this._view.isValid) return

        this._view = new cc.Node('TopBlock')
        this._view.opacity = 0
        AppUtil.setWidget(this._view)
        this._view.addComponent(cc.BlockInputEvents)
    }
}

修改UIMgr.ts脚本,在加载UI资源可能有延迟的地方调用TopBlock.show()方法,结束的地方调用TopBlock.hide()方法。

编辑framework/scripts/view/UIMgr.ts,修改show方法。

private static async show(cls: UIBase, uiArgs: any[]) {
    TopBlock.show()

    const viewName = cls.getClassName()

    let current = this._uis.get(viewName)
    if (!current) {
        current = cls
        current.uiName = viewName

        const [uiPrefab, err] = await AppUtil.asyncWrap<cc.Prefab>(ResMgr.load(current.bundleName, current.skinPath))
        if (err) {
            TopBlock.hide()
            console.error(`UIMgr.show loadRes skinPath:${current.skinPath} err:${err}`)
            return
        }

        current.init(uiArgs)
        current.skin = cc.instantiate(uiPrefab)
        current.initDone()

        this._uis.set(viewName, current)
    } else {
        current.reset(uiArgs)
    }

    this.startShowUI(current)
}

修改showUIAfter方法。

private static showUIAfter(current: UIBase) {
    TopBlock.hide()

    this._current = current
}

编辑scripts/UIMain.ts,重载onInitDone方法。

import TopBlock from "../framework/scripts/view/TopBlock"
import UIBase from "../framework/scripts/view/UIBase"
import UIMgr from "../framework/scripts/view/UIMgr"
import UIBag from "./UIBag"


export default class UIMain extends UIBase {
    public skinPath: string = 'UIMain'
    public cache: boolean = true


    protected onInitDone(): void {
        // 因为 UIMgr 在 onInitDone 生命周期结束后会调用 TopBlock.hide(), 所以为了测试这里加个 100 毫秒的延迟
        setTimeout(() => {
            TopBlock.show()
            cc.log('这个时候点击无效')
            setTimeout(() => {
                TopBlock.hide()
                cc.log('现在可以点击了')
            }, 10000)
        }, 100)
    }

    protected onButtonClick(button: cc.Node) {
        switch (button.name) {
            case 'BtnUIBag':
                UIMgr.open(UIBag)
                break
        }
    }
}

运行程序,发现Main界面刚开始是不能点击背包按钮的,等过了 10 秒后就能点击了。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!