local UIManager = {} local MESSAGE_BOX_PATH = "assets/prefabs/ui/common/message_box.prefab" local TUTORIAL_PATH = "assets/prefabs/ui/tutorial/tutorial_ui.prefab" UIManager.UI_TYPE = { DEFAULT = 0, MULTI = 1, -- 非唯一界面,此类型界面同一时间可以打开多个 MAIN = 2, -- 主要的界面,打开此界面的时候会关闭所有其他界面 } UIManager.MESSAGE_BOX_TAG = { BATTLE_SKIP = 1, LOGIN_FAIL = 2 } -- 个别uipath不同模块需要使用,统一写到一个地方避免后期要改的话改漏了 UIManager.UI_PATH = { GM_TOO_UI = "app/ui/gm/gm_tool_ui", MAINCITY_UI = "app/ui/main_city/main_city_ui", BATTLE_UI = "app/ui/battle/battle_ui", ROGUE_SKILL_UI = "app/ui/battle/battle_skill_select_ui", REWARD_BOX = "app/ui/tips/reward_box", HERO_DETAIL_UI = "app/ui/hero/hero_detail_ui", ARENA_MATCH_UI = "app/ui/arena/arena_match_ui", BATTLE_PVP_UI = "app/ui/battle/battle_ui_pvp", } -- 动画类型 UIManager.ANI_TYPE = { POP = 1, -- 弹出 NONE = 2, -- 无动画 } -- loading类型 UIManager.LOADING_TYPE = { BLACK = 1, CLOUD = 2 } -- ui缓存上限 local UI_CACHE_SIZE = 5 -- 根据以往项目的经验提前申请一个值,避免动态扩容导致的开销,可根据项目实际情况调整 local MAIN_CANVAS_HIERARCHY_CAPACITY = 20480 local MAIN_CANVAS_ORDER = 1000 local UI_INTERVAL_ORDER = 400 local UI_MAX_ORDER = 28000 local UI_BARS_UNDER_ORDER = 2 local CLICK_EFFECT = 31000 local OTHER_CANVAS_INTERVAL_ORDER = { TOAST = 1, TUTORIAL = 2, NET = 3, LOADING = 4, SWALLOW_TOUCH = 5, MESSAGE_BOX_TOP = 6, LOADING_TOP = 7, -- 这里要注意一下不要超过sortingOrder的最大值32767,目前UI_MAX_ORDER + UI_INTERVAL_ORDER * LOADING_TOP:28000 + 400 * 7 = 30800 小于 32767 } function UIManager:init(callback) if self.uiRoot and CS.BF.Utils.IsNull(self.uiRoot:getGameObject()) then return end self.uiList = {} self.loadingUI = {} self.uiCacheList = {} self.uiLoadedListeners = {} self.disableTouchCount = 0 self.waitNetCount = 0 UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/ui_root.prefab", nil, function(uiRoot) self.uiRoot = uiRoot CS.UnityEngine.GameObject.DontDestroyOnLoad(uiRoot:getGameObject()) local uiMap = uiRoot:genAllChildren() self.uiCamera = uiMap["ui_root.ui_camera"] self.mainCanvas = uiMap["ui_root.main_canvas"] self.mainCanvas:getTransform().hierarchyCapacity = MAIN_CANVAS_HIERARCHY_CAPACITY self.currencyRoot = uiMap["ui_root.main_canvas.currency_root"] self:_loadCurrencyBar() self.currencyCanvas = self.currencyRoot:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS) self.swallowUITouches = uiMap["ui_root.main_canvas.swallow_ui_touches"] self.swallowUITouchesCanvas = self.swallowUITouches:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS) self.toastCanvas = uiMap["ui_root.toast_canvas"] self.toastCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.TOAST self.toastNode = uiMap["ui_root.toast_canvas.toast"] self.messageBoxNode = uiMap["ui_root.toast_canvas.messagebox"] self.netCanvas = uiMap["ui_root.net_canvas"] local netCanvasOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.NET self.netCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = netCanvasOrder self.netCanvas:setActive(false) self.tutorialCanvas = uiMap["ui_root.tutorial_canvas"] self.tutorialCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.TUTORIAL self.loadingCanvas = uiMap["ui_root.loading_canvas"] self.blackLoadingImg = uiMap["ui_root.loading_canvas.black"] self.swallowTouchesCanvas = uiMap["ui_root.swallow_touches_canvas"] self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.SWALLOW_TOUCH -- ui预制件pool节点 self.uiPrefabPoolNode = uiMap["ui_root.ui_prefab_pool"] callback() end) end function UIManager:showUI(uiPath, params) if self.uiRoot == nil then return end local uiObj = self:checkOpen(uiPath) if uiObj then return uiObj end uiObj = require(uiPath):create(params) uiObj:setUIIndex(uiPath) uiObj:_recordParams(params) local topUISiblingIndex local topUI = self.uiList[#self.uiList] if topUI then topUISiblingIndex = topUI:getSiblingIndex() + 1 topUI:_onCover() else topUISiblingIndex = 1 end table.insert(self.uiList, uiObj) self:setUIOrder(uiObj, topUISiblingIndex) local aniType = self:getAniType(uiObj) if aniType then self:_setUISwallowOrder(topUISiblingIndex + 1) self.swallowUITouches:getGameObject():SetActive(true) else self:_updateUISwallowOrder() end uiObj:_onCreate() local bgm = uiObj:getBGMId() if bgm then self:playBGM(bgm) end Logger.logHighlight("Show UI:%s", uiPath) -- 上报打开界面事件 BIReport:postOpenUI(uiObj:getPrefabPath()) return uiObj end function UIManager:closeUI(uiObj) local uiNum = #self.uiList local removeIndex = 0 for i = uiNum, 1, -1 do if uiObj == self.uiList[i] then removeIndex = i break end end if removeIndex <= 0 then Logger.log(uiObj:getUIIndex(), " is not open") return end if removeIndex == uiNum then -- 需要关闭的界面在最上层 uiNum = uiNum - 1 if uiNum > 0 then local topUI = self.uiList[uiNum] topUI:_onReshow() local aniType = self:getAniType(uiObj) if aniType and aniType ~= UIManager.ANI_TYPE.POP and aniType ~= UIManager.ANI_TYPE.NONE then if removeIndex > 0 then table.remove(self.uiList, removeIndex) end self:_setUISwallowOrder(uiObj:getSiblingIndex() + 1) self.swallowUITouches:getGameObject():SetActive(true) uiObj:_playExitAnimation() else if removeIndex > 0 then table.remove(self.uiList, removeIndex) end uiObj:_onExitAnimationComplete() self:_updateUISwallowOrder() end local bgm = topUI:getBGMId() if bgm then self:playBGM(bgm) elseif uiObj:getBGMId() then local openedUINum = uiNum while openedUINum > 1 do openedUINum = openedUINum - 1 bgm = self.uiList[openedUINum]:getBGMId() if bgm then self:playBGM(bgm) break end end end else uiObj:_onExitAnimationComplete() end else if removeIndex > 0 then table.remove(self.uiList, removeIndex) end uiObj:_onExitAnimationComplete() if uiObj:isFullScreen() and uiObj:isVisible() then local curIndex = removeIndex - 1 local currObj = nil while curIndex >= 1 do currObj = self.uiList[curIndex] currObj:_setVisible(true) self:setBarsVisible(currObj, true) if currObj:isFullScreen() then break end curIndex = curIndex - 1 end end end uiObj:_onClose() end function UIManager:checkOpen(uiPath) local uiNum = #self.uiList if uiNum > 0 then for i = uiNum, 1, -1 do if self.uiList[i]:getUIIndex() == uiPath then -- 如果这个界面可以打开多个 if self.uiList[i]:getUIType() == UIManager.UI_TYPE.MULTI then return nil end if i < uiNum then -- 如果这个界面已经打开,并且不是最顶层 local reshowUI if self.uiList[i]:getUIType() == UIManager.UI_TYPE.MAIN then -- 关闭此界面之上所有界面 for j = uiNum, i + 1, -1 do local closeUIObj = table.remove(self.uiList, j) closeUIObj:_onClose() closeUIObj:_onExitAnimationComplete() end reshowUI = self.uiList[i] else -- 将此界面放到所有界面的最顶层 local topUI = self.uiList[uiNum] local siblingIndex = topUI:getSiblingIndex() + 1 topUI:_onCover() reshowUI = table.remove(self.uiList, i) table.insert(self.uiList, reshowUI) self:setUIOrder(reshowUI, siblingIndex) end self:_updateUISwallowOrder() reshowUI:_onReshow() local bgm = reshowUI:getBGMId() if bgm then self:playBGM(bgm) end return reshowUI end return self.uiList[i] end end end return nil end function UIManager:getUIPrefab(path, callback) for k, prefabObj in ipairs(self.uiCacheList) do if prefabObj:getAssetPath() == path then prefabObj:setParent(self.mainCanvas, false) table.remove(self.uiCacheList, k) return callback(prefabObj) end end UIPrefabManager:loadUIWidgetAsync(path, self.mainCanvas, callback) end function UIManager:clearUIPrefabCache() for i = 1,#self.uiCacheList do table.remove(self.uiCacheList):destroy() end end function UIManager:putbackUIPrefab(prefabObj) prefabObj:setParent(self.uiPrefabPoolNode, false) if #self.uiCacheList >= UI_CACHE_SIZE then -- 缓存的ui prefab已经超上限了 local head = table.remove(self.uiCacheList, 1) head:destroy() end table.insert(self.uiCacheList, prefabObj) end function UIManager:setUIOrder(uiObj, siblingIndex) local order = MAIN_CANVAS_ORDER + siblingIndex * UI_INTERVAL_ORDER if order < UI_MAX_ORDER then uiObj:setUIOrder(siblingIndex, order) else -- 超过最大值了,全部界面重新设置一下order for i, obj in ipairs(self.uiList) do order = MAIN_CANVAS_ORDER + i * UI_INTERVAL_ORDER obj:setUIOrder(i, order) end if self.currencyBarBindUI then local sortingOrder = self.currencyBarBindUI:getUIOrder() self.currencyCanvas.sortingOrder = sortingOrder + UI_INTERVAL_ORDER - UI_BARS_UNDER_ORDER end self:_updateUISwallowOrder() end end function UIManager:setBarsVisible(uiObj, visible) if self.currencyBarBindUI == uiObj then if self.currencyBar then self.currencyBar:setVisible(visible) end end end function UIManager:updateBarsState(uiObj) if self.currencyBarBindUI == uiObj then self:showCurrencyBar(uiObj) end end function UIManager:hideBehindUI(uiObj) local findIndex = 0 for i = #self.uiList, 1, -1 do if uiObj == self.uiList[i] then findIndex = i break end end local curIndex = findIndex - 1 local currObj = nil while curIndex >= 1 do currObj = self.uiList[curIndex] if currObj:isVisible() == false then break end currObj:_setVisible(false) self:setBarsVisible(currObj, false) curIndex = curIndex - 1 end end function UIManager:showBehindUI(uiObj) local findIndex = 0 for i = #self.uiList, 1, -1 do if uiObj == self.uiList[i] then findIndex = i break end end local curIndex = findIndex - 1 local currObj = nil while curIndex >= 1 do currObj = self.uiList[curIndex] currObj:_setVisible(true) self:setBarsVisible(currObj, true) if currObj:isFullScreen() then break end curIndex = curIndex - 1 end end function UIManager:getUIByIndex(index) for k, v in ipairs(self.uiList) do if v:getUIIndex() == index then return v end end return nil end -- 获取引导UI function UIManager:getTutorial(callback) if self.tutorial == nil then UIPrefabManager:loadUIWidgetAsync(TUTORIAL_PATH, self.tutorialCanvas, function (prefabObject) if self.tutorial then prefabObject:destroy() return end self.tutorial = prefabObject if callback then callback(prefabObject) end end) else self.tutorial:setActive(true) if callback then callback(self.tutorial) end end end -- 显示引导节点 function UIManager:showTutorial() self.tutorialCanvas:setActive(true) end -- 隐藏引导节点 function UIManager:hideTutorial() self.tutorialCanvas:setActive(false) end function UIManager:getBlackLoadingImg() return self.blackLoadingImg end function UIManager:showLoading(loadingType, callback) self:disableTouch() self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.LOADING loadingType = loadingType or UIManager.LOADING_TYPE.BLACK if self.currLoadingType == nil then self.currLoadingType = loadingType end ModuleManager.LoadingManager:showLoading(loadingType, self.loadingCanvas, callback) end function UIManager:closeLoading(callback) if self.currLoadingType == nil then self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false if callback then callback() end return false end ModuleManager.LoadingManager:closeLoading(self.currLoadingType, function () self:onLoadingUICompletelyClosed() if callback then callback() end end) self.currLoadingType = nil return true end function UIManager:onLoadingUICompletelyClosed() self:enableTouch() self.loadingCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end function UIManager:closeAllUI() local uiNum = #self.uiList for i = uiNum, 1, -1 do self.uiList[i]:_onClose() self.uiList[i]:_onExitAnimationComplete() end self.uiList = {} self.currencyBarBindUI = nil if self.currencyBar then self.currencyBar:setVisible(false) end end function UIManager:closeAllUIExceptMainUI(includeCurrencyBar) local uiNum = #self.uiList for i = uiNum, 1, -1 do if self.uiList[i]:getUIIndex() ~= UIManager.UI_PATH.MAINCITY_UI then self.uiList[i]:_onClose() self.uiList[i]:_onExitAnimationComplete() table.remove(self.uiList, i) end end if includeCurrencyBar and self.currencyBar then self.currencyBarBindUI = nil self.currencyBar:setVisible(false) end end function UIManager:hideMainUIExceptBattle() local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI) if uiObj and uiObj:getIsLoadedComplete() then uiObj:hideMainUIExceptBattle() end end function UIManager:showMainUIExceptBattle() local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI) if uiObj and uiObj:getIsLoadedComplete() then uiObj:showMainUIExceptBattle() end end -- 测试专用,有隐患,正常逻辑不要直接使用 function UIManager:reshowAllUI() if DEBUG and EDITOR_MODE then local reshowList = {} for k, v in ipairs(self.uiList) do reshowList[k] = v end self:closeAllUI() for i = 1, #reshowList do local params = reshowList[i]:_getRecordParams() if params and type(params) == "table" then params.aniType = nil end self:showUI(reshowList[i]:getUIIndex(), params) end end end function UIManager:closeBehindUI(uiObj) local closeFlag = false for i = #self.uiList, 1, -1 do local curUIObj = self.uiList[i] if closeFlag then table.remove(self.uiList, i) curUIObj:_onClose() curUIObj:_onExitAnimationComplete() else if curUIObj == uiObj then closeFlag = true end end end if closeFlag then self:_updateUISwallowOrder() end end function UIManager:closeUnderUI(uiObj) local closeFlag = false for i = 1, #self.uiList do local curUIObj = self.uiList[i] if curUIObj == uiObj then for j = #self.uiList, i + 1, -1 do curUIObj = self.uiList[j] table.remove(self.uiList, j) curUIObj:_onClose() curUIObj:_onExitAnimationComplete() closeFlag = true end break end end if closeFlag then uiObj:_onReshow() self:_updateUISwallowOrder() end end function UIManager:onUILoadedComplete(uiObj) local callback = self.uiLoadedListeners[uiObj:getUIIndex()] if callback then self.uiLoadedListeners[uiObj:getUIIndex()] = nil callback() end end function UIManager:onUIClosedComplete(uiObj) self:updateBarsWhenCloseUI(uiObj) if self.uiLoadedListeners[uiObj:getUIIndex()] then self.uiLoadedListeners[uiObj:getUIIndex()] = nil end end function UIManager:addLoadUICompleteListener(uiIndex, callback) local uiObj = self:getUIByIndex(uiIndex) if uiObj and uiObj._baseLoadComplete then callback() else self.uiLoadedListeners[uiIndex] = callback end end function UIManager:getMessageBox(top, callback) if top then if self.topMsgBox == nil then UIPrefabManager:loadUIWidgetAsync(MESSAGE_BOX_PATH, self.messageBoxNode, function (prefabObject) if self.topMsgBox then prefabObject:destroy() callback(self.topMsgBox) return end prefabObject:initPrefabHelper() prefabObject:getTransform():SetAsLastSibling() local messageBoxCanvas = prefabObject:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS) local messageBoxCanvasOrder = UI_MAX_ORDER + UI_INTERVAL_ORDER*OTHER_CANVAS_INTERVAL_ORDER.MESSAGE_BOX_TOP messageBoxCanvas.overrideSorting = true messageBoxCanvas.sortingOrder = messageBoxCanvasOrder self.topMsgBox = prefabObject callback(prefabObject) end) else self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true callback(self.topMsgBox) end else if self.messageBox == nil then UIPrefabManager:loadUIWidgetAsync(MESSAGE_BOX_PATH, self.messageBoxNode, function (prefabObject) if self.messageBox then prefabObject:destroy() callback(self.messageBox) return end prefabObject:initPrefabHelper() self.messageBox = prefabObject callback(prefabObject) end) else self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true callback(self.messageBox) end end end function UIManager:getMessageBoxGameObject(top) if top then return self.topMsgBox else return self.messageBox end end function UIManager:getMessageBoxCanvas() return self.messageBoxNode:getTransform() end function UIManager:hideMessageBox() if self.messageBox then self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end end function UIManager:hideMessageBoxByTag(tag) if self.messageBox then if self.messageBox:getTag() == tag then self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end end if self.topMsgBox then if self.topMsgBox:getTag() == tag then self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end end end function UIManager:getToast(callback) if not self.toastPool then self.toastPool = {} end local toast for _, toastObj in ipairs(self.toastPool) do if not toastObj._using then toast = toastObj end end if toast == nil then UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/toast.prefab", self.toastNode, function (_prefabObject) _prefabObject:initPrefabHelper() table.insert(self.toastPool, _prefabObject) callback(_prefabObject) end) else callback(toast) end end function UIManager:getTaskToast(callback) if self.taskToast == nil then UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/task_toast.prefab", self.toastNode, function (_prefabObject) _prefabObject:initPrefabHelper() self.taskToast = _prefabObject callback(_prefabObject) end) else callback(self.taskToast) end end function UIManager:getAllToast() return self.toastPool end function UIManager:hideToast() if self.toastPool then ModuleManager.ToastManager:clear() for i, toastObj in ipairs(self.toastPool) do if toastObj._toastSequence then toastObj._toastSequence:Kill() toastObj._toastSequence = nil end toastObj._using = false toastObj:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end end if self.taskToast then ModuleManager.ToastManager:clear() end end function UIManager:showUpdateToast(msgData) local ts = msgData.ts // 1000 GFunc.showUpdateToast(ts - Time:getServerTime()) end function UIManager:getRollToast(callback) if not self.rollToast then UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/roll_toast.prefab", self.toastNode, function (_prefabObject) if self.rollToast then _prefabObject:destroy() return end _prefabObject:initPrefabHelper() self.rollToast = _prefabObject callback(_prefabObject) end) else callback(self.rollToast) end end ---- 回到登录界面时 killseq为true function UIManager:hideRollToast(killSeq) if not self.rollToast then return end if killSeq and self.rollToast._toastSequence then self.rollToast._toastSequence:Kill() self.rollToast._toastSequence = nil end ModuleManager.RollToastManager:clear(not killSeq) self.rollToast:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end function UIManager:hideToastAndMessageBox() self:hideToast() self:hideRollToast() end function UIManager:getMainCanvasTransform() return self.mainCanvas:getTransform() end function UIManager:getMainCanvas() return self.mainCanvas end function UIManager:getUICameraComponent() return self.uiCamera:getComponent(GConst.TYPEOF_UNITY_CLASS.CAMERA) end function UIManager:showWaitPay() if self.waitNetCount == 0 then if self.waitPaySeq == nil then local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.WAIT_PAY) seq:SetAutoKill(false) seq:AppendInterval(1) seq:AppendCallback(function() self.netCanvas:setActive(true) end) self.waitPaySeq = seq elseif not self.waitPaySeq:IsPlaying() then self.waitPaySeq:Restart() end end self.waitNetCount = self.waitNetCount + 1 self:disableTouch() end function UIManager:hideWaitPay() self:hideWaitNet() if self.waitNetCount <= 0 then if self.waitPaySeq then self.waitPaySeq:Pause() end end end function UIManager:showWaitNet(forceRestart) if self.waitNetCount == 0 or forceRestart then if self.waitNetSeq == nil then local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.WAIT_NET) seq:SetAutoKill(false) seq:AppendInterval(1) seq:AppendCallback(function() self.netCanvas:setActive(true) end) seq:AppendInterval(GConst.WAIT_NET_RSP_TIME) seq:OnComplete(function() -- 一段时间后还没收到回复就断开连接 NetManager:disconnectAndReconnect() end) self.waitNetSeq = seq elseif not self.waitNetSeq:IsPlaying() then self.waitNetSeq:Restart() end end self.waitNetCount = self.waitNetCount + 1 self:disableTouch() end function UIManager:hideWaitNet(hideAll) if hideAll then local count = self.waitNetCount self.waitNetCount = 0 if self.waitNetSeq then self.waitNetSeq:Pause() end self.netCanvas:setActive(false) for i = 1, count do self:enableTouch() end else if self.waitNetCount > 0 then self:enableTouch() end self.waitNetCount = self.waitNetCount - 1 if self.waitNetCount <= 0 then self.waitNetCount = 0 if self.waitNetSeq then self.waitNetSeq:Pause() end self.netCanvas:setActive(false) end end end function UIManager:getWaitNetCount() return self.waitNetCount end function UIManager:disableTouch() if self.disableTouchCount == 0 then self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = true end self.disableTouchCount = self.disableTouchCount + 1 if self.disableTouchCount <= 0 then Logger.logError("UIManager:disableTouch count error:%d", self.disableTouchCount) end end function UIManager:enableTouch() self.disableTouchCount = self.disableTouchCount - 1 if self.disableTouchCount <= 0 then self.swallowTouchesCanvas:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled = false end end function UIManager:_updateUISwallowOrder() local topSwallowTouchIndex = 0 for i = #self.uiList, 1, -1 do if self.uiList[i]:swallowTouchBetweenUI() then topSwallowTouchIndex = self.uiList[i]:getSiblingIndex() self:_setUISwallowOrder(topSwallowTouchIndex) break end end self.swallowUITouches:getGameObject():SetActive(topSwallowTouchIndex > 0) end function UIManager:_setUISwallowOrder(siblingIndex) local order = MAIN_CANVAS_ORDER + siblingIndex * UI_INTERVAL_ORDER self.swallowUITouches:getTransform():SetSiblingIndex(siblingIndex - 1) self.swallowUITouchesCanvas.sortingOrder = order - 1 end function UIManager:_getUpperUIObj(uiObj) local uiNum = #self.uiList for i = uiNum, 1, -1 do if self.uiList[i] == uiObj then return self.uiList[i - 1] end end return nil end function UIManager:getTopUIObj() local uiNum = #self.uiList return self.uiList[uiNum] end function UIManager:getTopUIIndex() if not self:getTopUIObj() then return end return self:getTopUIObj():getUIIndex() end function UIManager:getUIList() return self.uiList end function UIManager:getAniType(uiObj) local params = uiObj:_getRecordParams() if type(params) == "table" and params.aniType then return params.aniType end if not uiObj:isFullScreen() then return self.ANI_TYPE.POP end return nil end function UIManager:playBGM(id) if id ~= self.currBGMId then self.currBGMId = id AudioManager:playMusic(id, true) end end function UIManager:stopBGM(id) if id == self.currBGMId then self.currBGMId = nil AudioManager:stopMusicById(id, true) end end function UIManager:stopCurrentBGM() if self.currBGMId then AudioManager:stopMusicById(self.currBGMId, true) self.currBGMId = nil end end function UIManager:getCurrentBGM() return self.currBGMId end function UIManager:clear() if self.waitNetSeq then self.waitNetSeq:Kill() self.waitNetSeq = nil end end function UIManager:destroyUIRoot() if self.uiRoot then self.uiRoot:destroy() self.uiRoot = nil end end -- 显示刘海屏(模拟IphoneX) function UIManager:showNotchScreen() if self.notchScreen then self.notchScreen:setActive(true) else -- 创建一个刘海屏 local notchHeight = SafeAreaManager:getNotchScreenHeight() Logger.log("模拟刘海屏高度:%s", notchHeight) local notchScreen = CS.UnityEngine.GameObject("NotchScreen") notchScreen:AddComponent(GConst.TYPEOF_UNITY_CLASS.RECTTRANSFORM) self.notchScreen = BaseObject:create() self.notchScreen:initWithGameObject(notchScreen) self.notchScreen:getTransform():SetParent(self.toastCanvas:getTransform()) self.notchScreen:getTransform().anchorMin = BF.Vector2(0, 1) self.notchScreen:getTransform().anchorMax = BF.Vector2(1, 1) self.notchScreen:getTransform().pivot = BF.Vector2(0.5, 1) self.notchScreen:setAnchoredPosition(0, 0) self.notchScreen:setSizeDelta(0, notchHeight) self.notchScreen:setLocalScale(1, 1, 1) local cacheLocalPos = self.notchScreen:getTransform().localPosition self.notchScreen:getTransform().localPosition = BF.Vector3(cacheLocalPos.x, cacheLocalPos.y, 0) local img = notchScreen:AddComponent(GConst.TYPEOF_UNITY_CLASS.UI_IMAGE) img.color = BF.Color(0, 0, 0, 0.5) end end function UIManager:backToLogin() self:stopCurrentBGM() SDKManager:logout() -- 清除引导 ModuleManager.TutorialManager:stopTutorial() self:closeAllUI() ModuleManager.BattleManager:clearOnExitScene() Game:showLoginUI() end function UIManager:backToLoginWithoutLogout() self:stopCurrentBGM() ModuleManager.TutorialManager:stopTutorial() self:closeAllUI() ModuleManager.BattleManager:clearOnExitScene() Game:showLoginUI() end -- 掉线提示处理 function UIManager:showKickOut(msgData) local content local reason = NetManager:getKickOutReasonEnum(msgData.reason) if reason == 0 then -- 服务器维护 content = I18N:getGlobalText(I18N.GlobalConst.MAINTAIN) elseif reason == 1 then -- 网络消息流控,也就是短时间内通信次数太多 content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN) elseif reason == 2 then -- 封号 content = I18N:getGlobalText(I18N.GlobalConst.FORBIDDEN) elseif reason == 3 then -- 多点登录 content = I18N:getGlobalText(I18N.GlobalConst.OTHER_LOGIN) else content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN) end self.disconnectMsgBoxVisible = true -- 被踢了的话就先断开连接再弹确认框 NetManager:closeAndClear() local params = { content = content, okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), okFunc = function() self.disconnectMsgBoxVisible = false ModuleManager.LoginManager:goToLoginScene() end, boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, top = true, } GFunc.showMessageBox(params) end -- 掉线提示处理 function UIManager:showDisconnect() self.disconnectMsgBoxVisible = true local params = { content = I18N:getGlobalText(I18N.GlobalConst.DISCONNECT_RELOGIN), okText = I18N:getGlobalText(I18N.GlobalConst.BTN_TEXT_OK), okFunc = function() self.disconnectMsgBoxVisible = false ModuleManager.LoginManager:goToLoginScene() end, boxType = GConst.MESSAGE_BOX_TYPE.MB_OK, top = true, } GFunc.showMessageBox(params) end function UIManager:isDisconnectMsgBoxVisible() return self.disconnectMsgBoxVisible end function UIManager:_loadCurrencyBar(params, showBg, hidAddImg) if self.currencyBar == nil then UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/common/currency_bar.prefab", self.currencyRoot, function (_prefabObject) if self.currencyBar then _prefabObject:destroy() else self.currencyBar = _prefabObject:addLuaComponent(GConst.TYPEOF_LUA_CLASS.CURRENCY_BAR) end self.currencyBar:show(params, showBg, hidAddImg) end) end end function UIManager:showCurrencyBar(uiObj) local params, showBg, hidAddImg = uiObj:getCurrencyParams() if params then local currCurrencyBarOrder = 0 if self.currencyBarBindUI then currCurrencyBarOrder = self.currencyBarBindUI:getUIOrder() end local sortingOrder = uiObj:getUIOrder() if sortingOrder >= currCurrencyBarOrder then self.currencyBarBindUI = uiObj -- 设置为比下一个界面的order低x点 self.currencyCanvas.sortingOrder = sortingOrder + UI_INTERVAL_ORDER - UI_BARS_UNDER_ORDER if self.currencyBar == nil then self:_loadCurrencyBar(params, showBg, hidAddImg) else self.currencyBar:show(params, showBg, hidAddImg) end return true elseif sortingOrder == currCurrencyBarOrder then -- 同界面 if self.currencyBar then self.currencyBar:show(params, showBg, hidAddImg) else -- self.currencyParam = params self:_loadCurrencyBar(params, showBg, hidAddImg) end return true end end return false end function UIManager:updateCurrentBattleType(battleType) local uiObj = UIManager:getUIByIndex(UIManager.UI_PATH.MAINCITY_UI) if uiObj and uiObj:getIsLoadedComplete() then uiObj:updateCurrentBattleType(battleType) end end function UIManager:updateBarsWhenCloseUI(uiObj) if self.currencyBarBindUI == uiObj then -- 关闭的是跟顶部货币栏有关联的ui self.currencyBarBindUI = nil local updateFlag = false for i = #self.uiList, 1, -1 do if self:showCurrencyBar(self.uiList[i]) then updateFlag = true break end end if not updateFlag then if self.currencyBar then self.currencyBar:setVisible(false) end end end end function UIManager:refreshCurrencyBar() if self.currencyBar then self.currencyBar:refreshTextRightNow() end end function UIManager:refreshCurrencyAddTx(itemId, num) local topUI = self.uiList[#self.uiList] if self.currencyBar and self.currencyBarBindUI == topUI then self.currencyBar:refreshCurrencyAddTx(itemId, num) end end function UIManager:showCurrencyAction(pos, imgNum) local topUI = self.uiList[#self.uiList] if self.currencyBar and self.currencyBarBindUI == topUI then self.currencyBar:showCurrencyAction(pos, imgNum) end end function UIManager:showChatBtn(isFirstEnter) if self.uiRoot then if self.chatBtn then self.chatBtn:getLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP):show(isFirstEnter) else if self.isShowChat ~= nil then return end self.isShowChat = true UIPrefabManager:loadUIWidgetAsync("assets/prefabs/ui/chat/chat_btn.prefab", self.mainCanvas, function(prefab) self.chatBtn = prefab self.chatBtn:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).overrideSorting = true self.chatBtn:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).sortingOrder = UI_MAX_ORDER local comp = self.chatBtn:addLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP) if self.isShowChat then comp:show(isFirstEnter) else comp:hide() end self.isShowChat = nil end) end end end function UIManager:hideChatBtn() if self.uiRoot then if self.chatBtn then self.chatBtn:getLuaComponent(GConst.TYPEOF_LUA_CLASS.CHAT_BTN_COMP):hide() elseif self.isShowChat then self.isShowChat = false end end end -- 切换语言后刷新一些缓存的界面 function UIManager:refreshOnChangeLanguage() if self.currencyBar then self.currencyBar:refreshText() end local MessageBox = require "app/ui/common/message_box" if self.messageBox then MessageBox:refreshText(false) end if self.topMsgBox then MessageBox:refreshText(true) end ModuleManager.ToastManager:refreshText() ModuleManager.TaskToastManager:refreshText() end if EDITOR_MODE then UIManager._editorUpdateUISwallowOrder = UIManager._updateUISwallowOrder function UIManager:_updateUISwallowOrder() self:_editorUpdateUISwallowOrder() if self.mainCanvas:getTransform().hierarchyCapacity > MAIN_CANVAS_HIERARCHY_CAPACITY then Logger.logTodo("current main ui canvas hierarchyCount is:%d", self.mainCanvas:getTransform().hierarchyCapacity) end end end if NOT_PUBLISH then UIManager._releaseEnableTouch = UIManager.enableTouch function UIManager:enableTouch() if self._debugEnableTouchFuncMap == nil then self._debugEnableTouchFuncMap = { [SceneManager.onFinished] = true, [BaseUI.enableUITouch] = true, [BaseScene.enableTouch] = true, [UIManager.onLoadingUICompletelyClosed] = true, [UIManager.hideWaitNet] = true } end local currFunc = debug.getinfo(2, "f").func if self._debugEnableTouchFuncMap[currFunc] == nil then Logger.logFatal("you can not call UIManager:enableTouch directly") end self:_releaseEnableTouch() end UIManager._releaseDisableTouch = UIManager.disableTouch function UIManager:disableTouch() if self._debugDisableTouchFuncMap == nil then self._debugDisableTouchFuncMap = { [SceneManager.changeScene] = true, [BaseUI.disableUITouch] = true, [BaseScene.disableTouch] = true, [UIManager.showLoading] = true, [UIManager.showWaitNet] = true, [UIManager.showWaitPay] = true } end local currFunc = debug.getinfo(2, "f").func if self._debugDisableTouchFuncMap[currFunc] == nil then Logger.logFatal("you can not call UIManager:disableTouch directly") end self:_releaseDisableTouch() end end function UIManager:onPressAndroidBackspace() if self.uiRoot == nil then return end if self.disableTouchCount > 0 then return end if DataManager == nil then return end if DataManager.TutorialData:getIsInTutorial() then return end if DataManager.TutorialData:getIsFuncTutorial() then return end if self.topMsgBox and self.topMsgBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled then if self.topMsgBox._closeByAndroidBackspace then local MessageBox = require "app/ui/common/message_box" local uiMap = self.topMsgBox:genAllChildren() MessageBox:closeAndClear(self.topMsgBox, uiMap) end return end if self.messageBox and self.messageBox:getComponent(GConst.TYPEOF_UNITY_CLASS.CANVAS).enabled then if self.messageBox._closeByAndroidBackspace then local MessageBox = require "app/ui/common/message_box" local uiMap = self.messageBox:genAllChildren() MessageBox:closeAndClear(self.messageBox, uiMap) end return end if #self.uiList <= 0 then return end local topUI = self.uiList[#self.uiList] if topUI:isClosed() then return end if topUI.root == nil then return end if topUI.root:isDestroyed() then return end if not topUI:isVisible() then return end if not topUI:getIsShowComplete() then return end topUI:onPressBackspace() end return UIManager