miduo_client/Assets/ManagedResources/~Lua/Framework/Manager/UIManager.lua

692 lines
24 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

UIManager = {}
local this = UIManager
--监听ui事件的对象
this.eventSystem = nil
--正常UI面板节点
this.uiNode = nil
--固定层级面板节点
this.maxNode = nil
--UI的配置信息
this.configs = {}
--桟式UI列表
this.stackList = {}
--固定层级UI列表
this.fixedList= {}
--已经打开过的UI
this.openedList= {}
--窗口之间的层级间隔
this.space = 100
local UIConfig
local unpack = unpack
local standard = 16 / 9
local DELAY_TIME = 15 --超过延迟时间,界面被销毁
local delayDestoryList = {}
local function update()
for k,v in pairs(delayDestoryList) do
if v.delayTime < Time.realtimeSinceStartup then
this.DestroyPanel(v.panel)
this.openedList[k] = nil
delayDestoryList[k] = nil
end
end
end
UIType = {
--[[
全屏面板
打开:自动关闭桟中的所有全屏窗口,并将当前窗口提到桟顶
关闭:自动打开上一个全屏窗口
--]]
FullType = 1,
--[[
弹出框类型面板
打开:打开当前面板
关闭:关闭当前面板
--]]
Popup = 2,
--固定层级面板
--[[
弹出框类型面板
打开:打开当前面板
关闭:关闭当前面板
--]]
Fixed = 3
}
function UIManager.Initialize()
UIConfig = ConfigManager.GetConfig(ConfigName.UIConfig)
local prefab = resMgr:LoadAsset("UIRoot")
local gameObj = GameObject.Instantiate(prefab)
gameObj.name = "UIRoot"
this.eventSystem = GameObject.Find("EventSystem")
this.uiRoot = gameObj
this.uiNode = gameObj.transform:Find("UIRoot/UINode")
this.fullNode = gameObj.transform:Find("UIRoot/FullNode")
this.fixedNode = gameObj.transform:Find("UIRoot/FixedNode")
this.screenMask1 = gameObj.transform:Find("UIRoot/ScreenMask1").gameObject
this.screenMask2 = gameObj.transform:Find("UIRoot/ScreenMask2").gameObject
this.camera = gameObj.transform:Find("UICamera"):GetComponent("Camera")
this.Adapter()
this.InitCommonPanels()
UpdateBeat:Add(update, this)
-- RoleRenderManager.Init()
end
function UIManager.InitCommonPanels()
require("Modules/Message/MsgPanel")
require("Modules/Message/RequestPanel")
require("Modules/Message/LoadingPanel")
require("Modules/Message/PopupTipPanel")
require("Modules/Message/SwitchPanel")
require("Modules/Message/NotEnoughPopup")
require("Modules/Popup/CostConfirmPopup")
require("Modules/Message/HorseRaceLampView")
require("Modules/Message/MissionDailyTipPanel")
UIManager.OpenPanel(UIName.HorseRaceLampView)
end
function UIManager.Adapter()
local notchHeight = 0
local notchBottomHeight = 0
if AppConst.isSDK then
notchHeight = NotchScreenUtil.Instance:GetNotchHeight()
notchBottomHeight = NotchScreenUtil.Instance:GetNotchBottomHeight()
Log("********************* 刘海屏的高度是:"..notchHeight)
Log("********************* 刘海屏的底部区域高度是:"..notchBottomHeight)
--TODO: 这里再配置一套小众的手机的屏幕高度
if notchHeight == -1 then
notchHeight = 0
end
if notchBottomHeight == -1 then
notchBottomHeight = 0
end
end
UIManager.Offset = {
Top = notchHeight,
Bottom = notchBottomHeight,
Left = 0,
Right = 0,
}
-- 屏幕大小
UIManager.width = Screen.width
UIManager.height = Screen.height
-- 计算比例因子 比例因子 = 10^((lg(屏幕宽/开发宽)+lg(屏幕高/开发高)/2))
local log = math.log( Screen.width / 1080, 10) + math.log(Screen.height / 1920, 10)
local avg = log/2
local ft = math.pow(10, avg)
-- 实际分辨率 = 屏幕分辨率 / 比例因子
UIManager.UIHeight = Screen.height / ft
UIManager.UIWidth = Screen.width / ft
-- 计算屏幕比例的比值,用于部分界面进行屏幕适配的缩放
UIManager.adapterScale = (1920/1080)/(Screen.height / Screen.width)
-- ui实际大小
UIManager.realHeigt = Screen.height - UIManager.Offset.Top - UIManager.Offset.Bottom
UIManager.realWidth = Screen.width - UIManager.Offset.Left - UIManager.Offset.Right
local n = Screen.height / Screen.width
if n > standard then
local rectTransform = this.uiNode.gameObject:GetComponent("RectTransform")
rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x, rectTransform.offsetMin.y + UIManager.Offset.Bottom)
rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x, rectTransform.offsetMax.y - UIManager.Offset.Top)
-- rectTransform = this.screenMask1:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(0, 1)
-- rectTransform.anchorMax = Vector2.New(1, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.pivot = Vector2.New(0.5, 1)
-- rectTransform.sizeDelta = Vector2.New(0, UIManager.Offset.Top)
-- rectTransform = this.screenMask2:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(0, 0)
-- rectTransform.anchorMax = Vector2.New(1, 0)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.pivot = Vector2.New(0.5, 0)
-- rectTransform.sizeDelta = Vector2.New(0, UIManager.Offset.Bottom)
elseif n < standard then
-- 计算屏幕比例的比值,用于部分界面进行屏幕适配的缩放
UIManager.adapterScale = 1
local w = 1920 / Screen.height * Screen.width
local f = (w-1080) / 2
UIManager.Offset.Left = f
UIManager.Offset.Right = f
local rectTransform = this.uiNode.gameObject:GetComponent("RectTransform")
rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x + f, rectTransform.offsetMin.y)
rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x - f, rectTransform.offsetMax.y)
rectTransform = this.fixedNode.gameObject:GetComponent("RectTransform")
rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x + f, rectTransform.offsetMin.y)
rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x - f, rectTransform.offsetMax.y)
local fw = UIManager.UIWidth/2 - f
rectTransform = this.screenMask1:GetComponent("RectTransform")
rectTransform.anchoredPosition = Vector2.New(-fw, 0)
-- rectTransform.anchorMin = Vector2.New(0, 0)
-- rectTransform.anchorMax = Vector2.New(0, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(f*2, 0)
rectTransform = this.screenMask2:GetComponent("RectTransform")
rectTransform.anchoredPosition = Vector2.New(fw, 0)
-- rectTransform.anchorMin = Vector2.New(1, 0)
-- rectTransform.anchorMax = Vector2.New(1, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(f*2, 0)
else
this.screenMask1:SetActive(false)
this.screenMask2:SetActive(false)
end
-- local n = Screen.height / Screen.width
-- if n > standard then
-- local f = (n-standard)*Screen.width / 2
-- local rectTransform = this.uiNode.gameObject:GetComponent("RectTransform")
-- rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x, rectTransform.offsetMin.y + f)
-- rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x, rectTransform.offsetMax.y - f)
-- rectTransform = this.fixedNode.gameObject:GetComponent("RectTransform")
-- rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x, rectTransform.offsetMin.y + f)
-- rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x, rectTransform.offsetMax.y - f)
-- rectTransform = this.screenMask1:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(0, 1)
-- rectTransform.anchorMax = Vector2.New(1, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(0, f*2)
-- rectTransform = this.screenMask2:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(0, 0)
-- rectTransform.anchorMax = Vector2.New(1, 0)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(0, f*2)
-- UIManager.width = Screen.width
-- UIManager.height = Screen.height - f*2
-- elseif n < standard then
-- local w = 1920 / Screen.height * Screen.width
-- local f = (w-1080) / 2
-- local rectTransform = this.uiNode.gameObject:GetComponent("RectTransform")
-- rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x + f, rectTransform.offsetMin.y)
-- rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x - f, rectTransform.offsetMax.y)
-- rectTransform = this.fixedNode.gameObject:GetComponent("RectTransform")
-- rectTransform.offsetMin = Vector2.New(rectTransform.offsetMin.x + f, rectTransform.offsetMin.y)
-- rectTransform.offsetMax = Vector2.New(rectTransform.offsetMax.x - f, rectTransform.offsetMax.y)
-- rectTransform = this.screenMask1:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(0, 0)
-- rectTransform.anchorMax = Vector2.New(0, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(f*2, 0)
-- rectTransform = this.screenMask2:GetComponent("RectTransform")
-- rectTransform.anchorMin = Vector2.New(1, 0)
-- rectTransform.anchorMax = Vector2.New(1, 1)
-- rectTransform.offsetMin = Vector2.New(0, 0)
-- rectTransform.offsetMax = Vector2.New(0, 0)
-- rectTransform.sizeDelta = Vector2.New(f*2, 0)
-- UIManager.width = Screen.width - f*2
-- UIManager.height = Screen.height
-- else
-- this.screenMask1:SetActive(false)
-- this.screenMask2:SetActive(false)
-- UIManager.height = Screen.height
-- UIManager.width = Screen.width
-- end
end
function UIManager.ChangeTo2D()
this.camera.orthographic = true
end
function UIManager.ChangeTo3D()
this.camera.orthographic = false
end
--打开面板
function UIManager.OpenPanel(id, ...)
-- 如果是
if id == UIName.BattlePanel and this.IsOpen(UIName.BattlePanel) then
LogError("战斗界面重复打开!!")
return
end
return UIManager.GetPanel(id, true, nil, ...)
end
--异步打开面板
function UIManager.OpenPanelAsync(id, func, ...)
UIManager.GetPanel(id, false, func, ...)
end
local SetSortingOrder = function(uiConfig, panel, isStackPanel, ...)
if isStackPanel then
if uiConfig.type == UIType.FullType then
for i = 1, #this.stackList do
if this.stackList[i] and this.stackList[i].isOpened then
this.stackList[i].gameObject:SetActive(false)
this.stackList[i]:CloseUI()
end
end
else
--上一个打开的窗口若是全屏窗口,则失去焦点
for i = #this.stackList, 1,-1 do
if this.stackList[i] and this.stackList[i].isOpened then
if this.stackList[i].uiConfig.type == UIType.FullType then
this.stackList[i]:LoseFocus()
end
break
end
end
end
this.stackList[#this.stackList+1] = panel
for i = 1, #this.stackList do
this.stackList[i].transform:SetAsLastSibling()
this.stackList[i]:SetSortingOrder(i * this.space)
end
else
this.fixedList[#this.fixedList+1] = panel
panel:SetSortingOrder(uiConfig.sortingOrder)
end
panel.gameObject:SetActive(true)
panel:OpenUI(false, ...)
panel.openNum = panel.openNum + 1
delayDestoryList[panel.uiConfig.id] = nil
end
function UIManager.GetPanel(id, isSync, func, ...)
local uiConfig = UIConfig[id]
if(uiConfig == nil) then
LogError("UIManager====>没有找到UI的配置信息:"..id)
return
end
local panel
local isStackPanel = uiConfig.type == UIType.FullType or uiConfig.type == UIType.Popup
local list = isStackPanel and this.stackList or this.fixedList
for i = 1, #list do
if list[i].uiConfig.id == uiConfig.id then
panel = list[i]
--如果找到了,从桟中移除
table.remove(list, i)
break
end
end
local args = {...}
local action = function(panel)
if not panel then --在缓存里面找一找
panel = this.openedList[uiConfig.id]
end
if not panel then
panel = reimport("Modules/"..uiConfig.script)
this.openedList[uiConfig.id] = panel
panel.uiConfig = uiConfig
local rootNode = this.fixedNode
if isStackPanel then
if uiConfig.type == UIType.FullType then
rootNode = this.uiNode
elseif uiConfig.type == UIType.Popup then
rootNode = this.fullNode
end
end
if isSync then
local gameObject = this.CreatePanel(uiConfig, rootNode)
panel:CreateUI(gameObject)
else
this.CreatePanelAsync(uiConfig, rootNode, function (gameObject)
panel:CreateUI(gameObject)
SetSortingOrder(uiConfig, panel, isStackPanel,unpack(args, 1, table.maxn(args)))
if func then
func(panel)
end
end)
end
end
if isSync then
SetSortingOrder(uiConfig, panel, isStackPanel,unpack(args, 1, table.maxn(args)))
return panel
else
if panel.gameObject then
SetSortingOrder(uiConfig, panel, isStackPanel,unpack(args, 1, table.maxn(args)))
end
end
end
if isStackPanel and uiConfig.type == UIType.FullType then --如果栈界面有需要播放关闭动画的界面,则新打开的界面需要等到关闭动画播放完成以后
local closeNum = 0
local closeTotal = 0
for i = 1, #this.stackList do
if this.stackList[i].isOpened and this.stackList[i].OnCloseBefore then
closeTotal = closeTotal + 1
this.stackList[i]:OnCloseBefore(function()
closeNum = closeNum + 1
if closeNum == closeTotal then
this.eventSystem:SetActive(true)
return action(panel)
end
end)
end
end
if closeTotal == 0 then
return action(panel)
else
this.eventSystem:SetActive(false)
end
else
return action(panel)
end
end
--界面是否已经打开过
function UIManager.IsOpen(id)
local uiConfig = UIConfig[id]
if(uiConfig==nil) then return end
local list
if(uiConfig.type == UIType.FullType or uiConfig.type == UIType.Popup) then
list = this.stackList
else
list = this.fixedList
end
for i=1,#list do
if(list[i].uiConfig.id == id and list[i].isOpened) then
return true
end
end
return false
end
-- 判断界面是否显示在最上层
function UIManager.IsTopShow(id)
local uiConfig = UIConfig[id]
if(uiConfig==nil) then return end
local list
if(uiConfig.type == UIType.FullType or uiConfig.type == UIType.Popup) then
list = this.stackList
else
list = this.fixedList
end
local len = #list
if list[len].uiConfig.id == id and list[len].isOpened then
return true
end
return false
end
--获取已经打开的面板
function UIManager.GetOpenPanel(id)
local uiConfig = UIConfig[id]
if(uiConfig==nil) then return end
local list
if(uiConfig.type == UIType.FullType or uiConfig.type == UIType.Popup) then
list = this.stackList
else
list = this.fixedList
end
for i=1,#list do
if(list[i].uiConfig.id == id) then
return list[i]
end
end
return nil
end
--关闭面板
function UIManager.ClosePanel(id,isDestroy)
if not id then
Log("UIManager.ClosePanel====>关闭面板id不能为空")
return
end
local uiConfig = UIConfig[id]
if(uiConfig == nil) then
Log("UIManager====>没有找到UI的配置信息:"..id)
return
end
isDestroy = isDestroy or uiConfig.noDestory == 0
if(uiConfig.type == UIType.FullType or uiConfig.type == UIType.Popup) then
this.CloseStackPanel(uiConfig,isDestroy)
else
this.CloseFixedPanel(uiConfig,isDestroy)
end
end
function UIManager.CloseFixedPanel(uiConfig,isDestroy)
if(#this.fixedList== 0) then return end
local panel
for i = 1, #this.fixedList do
if(this.fixedList[i].uiConfig.id == uiConfig.id) then
panel = this.fixedList[i]
table.remove(this.fixedList,i)
break
end
end
if(panel == nil) then return end
local closeAction = function()
if(panel.isOpened) then
panel.gameObject:SetActive(false)
panel:CloseUI()
end
if(isDestroy) then
this.DelayDestroyPanel(panel)
end
this.eventSystem:SetActive(true)
end
if panel.OnCloseBefore then
this.eventSystem:SetActive(false)
panel:OnCloseBefore(closeAction)
else
closeAction()
end
end
--关掉桟式面板
function UIManager.CloseStackPanel(uiConfig,isDestroy)
if(#this.stackList== 0) then return end
local panel = nil
for i = 1, #this.stackList do
if(this.stackList[i].uiConfig.id == uiConfig.id) then
panel = this.stackList[i]
table.remove(this.stackList,i)
break
end
end
if not panel then return end
local closeAction = function()
if panel.isOpened then
panel.gameObject:SetActive(false)
panel:CloseUI()
end
--如果是全屏窗口,向后回退到一个全屏窗口为止
if uiConfig.type == UIType.FullType then
-- 找到上一个全屏窗口的位置
local startIndex
for i = #this.stackList, 1,-1 do
local panel = this.stackList[i]
if panel.uiConfig.type == UIType.FullType then
startIndex = i
break
end
end
--
for i = startIndex, #this.stackList do
local panel = this.stackList[i]
if panel then
panel.gameObject:SetActive(true)
panel:OpenUI(true)
end
end
else
--回退的第一个打开的窗口若是全屏窗口,则被唤醒
for i = #this.stackList, 1,-1 do
if this.stackList[i].isOpened then
if this.stackList[i].uiConfig.type == UIType.FullType then
this.stackList[i]:Focus()
end
break
end
end
end
if isDestroy then
this.DelayDestroyPanel(panel)
end
this.eventSystem:SetActive(true)
end
if panel.OnCloseBefore then
this.eventSystem:SetActive(false)
panel:OnCloseBefore(closeAction)
else
closeAction()
end
end
--加载面板
function UIManager.CreatePanel(uiConfig, parent)
local prefab = resMgr:LoadAsset(uiConfig.assetName)
if prefab == nil then
LogError("资源创建失败!! 没有找到对应的资源!! key:"..uiConfig.id..",assetName:"..uiConfig.assetName)
resMgr:UnLoadAsset(uiConfig.assetName)
return
end
Log(uiConfig.assetName)
local gameObject = GameObject.Instantiate(prefab)
gameObject.name = prefab.name
local transform = gameObject.transform
transform:SetParent(parent)
transform.localScale = Vector3.one
local recTransform = transform:GetComponent("RectTransform")
recTransform.anchoredPosition3D = Vector3.New(0, 0, 0)
recTransform.sizeDelta = Vector2.New(0, 0)
transform.localRotation = Quaternion.identity
return gameObject
end
--异步加载面板
function UIManager.CreatePanelAsync(uiConfig, parent, func)
resMgr:LoadAssetAsync(uiConfig.assetName, function(name, prefab)
if prefab == nil then
LogError("资源创建失败!! 没有找到对应的资源!! key:"..uiConfig.id..",assetName:"..uiConfig.assetName)
resMgr:UnLoadAsset(uiConfig.assetName)
return
end
Log(uiConfig.assetName)
local gameObject = GameObject.Instantiate(prefab)
gameObject.name = prefab.name
local transform = gameObject.transform
transform:SetParent(parent)
transform.localScale = Vector3.one
local recTransform = transform:GetComponent("RectTransform")
recTransform.anchoredPosition3D = Vector3.New(0, 0, 0)
recTransform.sizeDelta = Vector2.New(0, 0)
transform.localRotation = Quaternion.identity
if func then
func(gameObject)
end
end)
end
--关闭所有面板
function UIManager.CloseAll(isDestroy)
local panel = nil
while(#this.stackList~=0)
do
panel = this.stackList[1]
panel.gameObject:SetActive(false)
panel:CloseUI()
if(isDestroy) then
this.DestroyPanel(panel)
end
table.remove(this.stackList,1)
end
while(#this.fixedList~=0)
do
panel = this.fixedList[1]
panel.gameObject:SetActive(false)
panel:CloseUI()
if(isDestroy) then
Log("UIManager.DestroyPanel")
this.DestroyPanel(panel)
end
table.remove(this.fixedList,1)
end
this.openedList = {}
delayDestoryList = {}
end
--延时销毁界面避免频繁的GC开销
function UIManager.DelayDestroyPanel(panel)
local item = delayDestoryList[panel.uiConfig.id]
if not item then
item = { delayTime = 0, panel = panel }
delayDestoryList[panel.uiConfig.id] = item
end
item.delayTime = Time.realtimeSinceStartup + DELAY_TIME * panel.openNum
end
function UIManager.DestroyPanel(panel)
panel:DestroyUI()
GameObject.Destroy(panel.gameObject)
resMgr:UnLoadAsset(panel.uiConfig.assetName)
resMgr:UnLoadUnUseAssetAndAssetBundle()
end
--获取UI配置
function UIManager.GetConfig(key)
return UIConfig[key]
end
--根据配置关闭游戏的所有面板
function UIManager.CloseAllGamePanel(uiConfig)
for i, v in pairs(uiConfig) do
UIManager.ClosePanel(v.id,true)
end
end
function UIManager.GetLocalPositionToTarget(parent,target)
local screenPos = this.camera:WorldToScreenPoint (target.transform.position)
local flag,targetPos = RectTransformUtility.ScreenPointToLocalPointInRectangle (parent.transform,screenPos,this.camera,nil)
return targetPos
end
function UIManager.Dispose()
UIManager.CloseAll(true)
GameObject.DestroyImmediate(this.uiRoot)
resMgr:UnLoadUnUseAssetAndAssetBundle()
end
return UIManager