local UIView = {} local UIBaseView = {} local EventSystem = require('Event/EventSystem') local UIViewSettings = require('Common/UIViewSettings') local UIScriptableCanvas = Tai.Lua.UIScriptableCanvas local CSFunc_StartRepeatFunc = CSExt.CSFunc_StartRepeatFunc local CSFunc_StopRepeatFunc = CSExt.CSFunc_StopRepeatFunc local CSFunc_ResetRepeatFunc = CSExt.CSFunc_ResetRepeatFunc local RegistTriggerEvent = CSExt.CSFunc_RegistTriggerEvent local UnregistTriggerEvent = CSExt.CSFunc_UnregistTriggerEvent local PlayUIAnimation = CSExt.CSFunc_PlayUIAnimation local StopUIAnimation = CSExt.CSFunc_StopUIAnimation local PauseUIAnimation = CSExt.CSFunc_PauseUIAnimation local ResumeUIAnimation = CSExt.CSFunc_ResumeUIAnimation local ScaleToSize = CSExt.CSFunc_ScaleToSize local MoveToPos = CSExt.CSFunc_MoveToPos local InstantiateCollection = CSExt.CSFunc_InstantiateCollection local DestroyCollection = CSExt.CSFunc_DestroyCollection local RegistDropEvent = CSExt.CSFunc_RegistDropEvent local RemoveTargetDropEvent = CSExt.CSFunc_RemoveTargetDropEvent local InstantiateCellCollection = CSExt.CSFunc_InstantiateCellCollection local InitUITemplate = CSExt.CSFunc_InitUITemplate local InitCellUITemplate = CSExt.CSFunc_InitCellUITemplate local SetSortingLayer = CSExt.CSFunc_SetSortingLayer local HierarchyFunctionCalls = {} local HierarchyBorderFunc = {} local rawget = rawget local function CallFunctionHierarchy(viewSelf, funcName, ...) --此方法可能出现递归调用,造成调用栈被污染,使用一个边界标记变量来分隔每一个函数的调用栈 table.insert(HierarchyFunctionCalls, HierarchyBorderFunc) local viewType = viewSelf.__viewType while viewType do local func = rawget(viewType, funcName) if func then table.insert(HierarchyFunctionCalls, func) end viewType = viewType.BaseViewType end --每次只遍历到边界就停止,剩下的是其它函数的调用栈 local func = table.remove(HierarchyFunctionCalls) while func ~= HierarchyBorderFunc do func(viewSelf, ...) func = table.remove(HierarchyFunctionCalls) end end local UIEventTriggerType = { PointerEnter = 0, PointerExit = 1, PointerDown = 2, PointerUp = 3, PointerClick = 4, Drag = 5, Drop = 6, Scroll = 7, UpdateSelected = 8, Select = 9, Deselect = 10, Move = 11, InitializePotentialDrag = 12, BeginDrag = 13, EndDrag = 14, Submit = 15, Cancel = 16, } local OnEventTriggerHandlerName = {} for eventName, eventIndex in pairs(UIEventTriggerType) do OnEventTriggerHandlerName[eventIndex] = "On"..eventName end local OnLoopScrollEventTriggerHandlerName = {} for eventName, eventIndex in pairs(UIEventTriggerType) do OnLoopScrollEventTriggerHandlerName[eventIndex] = "Cell_On"..eventName end --所有用于与C#之间通信的调用函数定义 local ViewEntryType = { OnCreated = 1, OnOpened = 2, OnClosed = 3, OnFocusChanged = 4, OnUIAnimationStoped = 5, OnButtonClicked = 6, OnValueChanged = 7, OnEndEdit = 8, OnEventTrigger = 9, OnLoopScrollEvent = 10, OnLoopScrollEventTrigger = 11, OnBackButtonPressed = 13, OnRepeatFunc = 20, InvokeEntryTypeStart = 30, GetViewClassName = 31, LSEvent_OnScrollTop = 1, LSEvent_OnScrollBottom = 2, LSEvent_OnCellInit = 3, LSEvent_OnCellSelect = 4, LSEvent_OnCellClicked = 5, LSEvent_OnCellMoveCenter = 6, LSEvent_OnCellValueChanged = 7, LSEvent_OnCellDispose = 8, } local ViewEntryFuncImpl = { [ViewEntryType.OnCreated] = function(self) CallFunctionHierarchy(self, "OnCreated") end, [ViewEntryType.OnOpened] = function(self, context) CallFunctionHierarchy(self, "OnOpened", context) end, [ViewEntryType.OnBackButtonPressed] = function(self) local viewFunc = self.OnBackButtonPressed if viewFunc then viewFunc(self) end end, [ViewEntryType.OnClosed] = function(self) CallFunctionHierarchy(self, "OnClosed") end, [ViewEntryType.OnFocusChanged] = function(self, value) EventSystem.Dispatch(EventID.UI_Guide_OnViewFocus, self.__viewClassPath, value) CallFunctionHierarchy(self, "OnFocusChanged", value) end, [ViewEntryType.OnUIAnimationStoped] = function(self, playingID) local viewFunc = self.OnUIAnimationStoped if viewFunc then viewFunc(self, playingID) end end, [ViewEntryType.OnButtonClicked] = function(self, comp) local viewFunc = self.OnButtonClicked if viewFunc then viewFunc(self, comp) end end, [ViewEntryType.OnValueChanged] = function(self, comp, value) local viewFunc = self.OnValueChanged if viewFunc then viewFunc(self, comp, value) end end, [ViewEntryType.OnEndEdit] = function(self, comp, value) local viewFunc = self.OnEndEdit if viewFunc then viewFunc(self, comp, value) end end, [ViewEntryType.OnEventTrigger] = function(self, eventType, eventComponent, eventData) local funcName = OnEventTriggerHandlerName[eventType] if funcName then local viewFunc = self[funcName] if viewFunc then viewFunc(self, eventComponent, eventData) else logging.error(LTAG.ERROR, 'view event trigger function not found:', funcName, eventComponent) end else logging.error(LTAG.ERROR, 'view event trigger type not found:', eventType, eventComponent) end end, [ViewEntryType.OnLoopScrollEvent] = function(self, lsEventType, ...) local viewFunc = nil if lsEventType == ViewEntryType.LSEvent_OnScrollTop then viewFunc = self.OnScrollTop elseif lsEventType == ViewEntryType.LSEvent_OnScrollBottom then viewFunc = self.OnScrollBottom elseif lsEventType == ViewEntryType.LSEvent_OnCellInit then viewFunc = self.OnCellInit elseif lsEventType == ViewEntryType.LSEvent_OnCellSelect then viewFunc = self.OnCellSelect elseif lsEventType == ViewEntryType.LSEvent_OnCellMoveCenter then viewFunc = self.OnCellMoveCenter elseif lsEventType == ViewEntryType.LSEvent_OnCellClicked then viewFunc = self.OnCellClicked elseif lsEventType == ViewEntryType.LSEvent_OnCellValueChanged then viewFunc = self.OnCellValueChanged elseif lsEventType == ViewEntryType.LSEvent_OnCellDispose then viewFunc = self.OnCellDispose else logging.error(LTAG.ERROR, 'loop scroll entry function event type not found:', lsEventType, ...) end if viewFunc then viewFunc(self, ...) end end, [ViewEntryType.OnLoopScrollEventTrigger] = function(self, eventType, comp, index, eventComponent, eventData) local funcName = OnLoopScrollEventTriggerHandlerName[eventType] if funcName then local viewFunc = self[funcName] if viewFunc then viewFunc(self, comp, index, eventComponent, eventData) else logging.error(LTAG.ERROR, 'loop scroll event trigger function not found:', funcName, comp, index, eventComponent) end else logging.error(LTAG.ERROR, 'loop scroll event trigger type not found:', eventType, comp, index, eventComponent) end end, [ViewEntryType.OnRepeatFunc] = function(self, repeatId, ...) local viewFunc = self.__repeatFunc[repeatId] if viewFunc then viewFunc(self, ...) else logging.error(LTAG.ERROR, 'view repeat func not found') end end, [ViewEntryType.GetViewClassName] = function(self) return self.__viewClassPath end } --界面提供给C#的入口函数 local function ViewEntryFunc(self, funcType, ...) local entryFunc = ViewEntryFuncImpl[funcType] if entryFunc then if funcType > ViewEntryType.InvokeEntryTypeStart then return entryFunc(self, ...) else entryFunc(self, ...) end else logging.error(LTAG.ERROR, 'view entry function type not found:', funcType, ...) end end --UIView Interface function UIBaseView:OnOpened(context) self.context = context -- 资源条统一处理 if CTL and CTL.Currency then CTL.Currency.OpenCurrencyPanel(self.__viewClassPath, self.currency_Info) end if DEF.USE_BATCH_MODE then BatchAgent.RegisterBatchUIEvent(self.__viewClassPath, self) end -- 打脸功能设置当前显示跳过状态 if CTL and CTL.PushInterface then CTL.PushInterface.ShowPushInterface(self.__viewClassPath, self.toggle_Skip) end EventSystem.Dispatch(EventID.UI_OnViewOpened, self.__viewClassPath) UIViewSettings.OnViewOpened(self) end function UIBaseView:OnBackButtonPressed() UIViewSettings.OnBackButtonPressed(self) end function UIBaseView:OnClosed() self:UnregistSystemEvent() self:UnregistTriggerEvent() self.__repeatFunc = nil if DEF.USE_BATCH_MODE then BatchAgent.UnRegisterBatchUIEvent(self.__viewClassPath, self) end EventSystem.Dispatch(EventID.UI_OnViewClosed, self.__viewClassPath) UIViewSettings.OnViewClosed(self) end function UIBaseView:RegistSystemEvent(eventId, func) self.__systemEventEntry = self.__systemEventEntry or {} table.insert(self.__systemEventEntry, {eventId, func, self}) EventSystem.Regist(eventId, func, self) end function UIBaseView:UnregistSystemEvent() if self.__systemEventEntry then for _, evt in ipairs(self.__systemEventEntry) do EventSystem.UnRegist(evt[1], evt[2], evt[3]) end self.__systemEventEntry = nil end end function UIBaseView:StartRepeatFunc(repeatFunc, interval, repeatCount, isUpdate, useRealTimeUpdate) if interval < 0 then logging.error(LTAG.ERROR, "view repeat function interval invalid!") return end if repeatCount == nil then repeatCount = 0 end if isUpdate == nil then isUpdate = true end if useRealTimeUpdate == nil then useRealTimeUpdate = true end if self.__repeatFunc == nil then local repeatId = CSFunc_StartRepeatFunc(self, interval, repeatCount, isUpdate, useRealTimeUpdate) --构建一个双向索引,在Lua中使用func作为键,在C#中使用id作为键 self.__repeatFunc = { [repeatFunc] = repeatId, [repeatId] = repeatFunc, } else local repeatId = self.__repeatFunc[repeatFunc] if repeatId then CSFunc_StopRepeatFunc(self, repeatId) self.__repeatFunc[repeatId] = nil self.__repeatFunc[repeatFunc] = nil end repeatId = CSFunc_StartRepeatFunc(self, interval, repeatCount, isUpdate, useRealTimeUpdate) self.__repeatFunc[repeatFunc] = repeatId self.__repeatFunc[repeatId] = repeatFunc end end function UIBaseView:StopRepeatFunc(repeatFunc) if self.__repeatFunc then local repeatId = self.__repeatFunc[repeatFunc] if repeatId then CSFunc_StopRepeatFunc(self, repeatId) self.__repeatFunc[repeatId] = nil self.__repeatFunc[repeatFunc] = nil end end end function UIBaseView:ResetRepeatFunc(repeatFunc, startAtTime) if self.__repeatFunc then local repeatId = self.__repeatFunc[repeatFunc] if repeatId then CSFunc_ResetRepeatFunc(self, repeatId, startAtTime or 0) end end end function UIBaseView:PlayUIAnimation(...) return PlayUIAnimation(self, ...) end function UIBaseView:StopUIAnimation(id, dispose, stopAtEnd, resetAfterStop) StopUIAnimation(self, id, dispose or false, stopAtEnd or false, resetAfterStop or false) end function UIBaseView:PauseUIAnimation(id) PauseUIAnimation(self, id) end function UIBaseView:ResumeUIAnimation(id) ResumeUIAnimation(self, id) end function UIBaseView:ScaleToSize(...) return ScaleToSize(self, ...) end function UIBaseView:MoveToPos(...) return MoveToPos(self, ...) end --用于给界面动态添加对象,需要一个Array类型的Collection并指定源对象,创建成功后返回生成的新对象 function UIBaseView:InstantiateCollection(parentCollection, sourceObj) local newCol = {} table.insert(parentCollection, newCol) InstantiateCollection(self, sourceObj, newCol, parentCollection.gameObject) return newCol end --移除一个Array类型Collection中的元素,界面关闭时所有动态创建的对象会一并销毁,没有特殊需求时不需要手动调用 function UIBaseView:DestroyCollection(parentCollection, index) table.remove(parentCollection, index) DestroyCollection(self, index - 1, parentCollection.gameObject) end --用于给界面动态添加对象,需要一个Array类型的Collection并指定源对象,创建成功后返回生成的新对象 function UIBaseView:InstantiateCellCollection(cellGameObject, parentCollection, sourceObj) local newCol = {} table.insert(parentCollection, newCol) InstantiateCellCollection(cellGameObject, sourceObj, newCol, parentCollection.gameObject) return newCol end -- 用于给界面动态初始化Template,初始化之前template节点是{gameObject = XXX},初始化后为具体的table function UIBaseView:InitUITemplate(uiTemplateTable, parentColTable) if parentColTable then InitUITemplate(self, uiTemplateTable, parentColTable) else InitUITemplate(self, uiTemplateTable) end end -- 用于给Cell动态初始化Template,初始化之前template节点是{gameObject = XXX},初始化后为具体的table function UIBaseView:InitCellUITemplate(cellGameObject, uiTemplateTable, parentColTable) if parentColTable then InitCellUITemplate(cellGameObject, uiTemplateTable, parentColTable) else InitCellUITemplate(cellGameObject, uiTemplateTable) end end function UIBaseView:CloseView(isRecoveryView) UIScriptableCanvas.ExecuteCloseViewEvent(self.gameObject, isRecoveryView or false) end function UIBaseView:RegistTriggerEvent(comp, eventType) self.__triggerEventEntry = self.__triggerEventEntry or {} self.__triggerEventEntry[comp] = true RegistTriggerEvent(self, comp, eventType, true) end function UIBaseView:UnregistTriggerEvent(comp) if self.__triggerEventEntry then if comp then if self.__triggerEventEntry[comp] then UnregistTriggerEvent(self, comp) self.__triggerEventEntry[comp] = nil end else for compTemp in pairs(self.__triggerEventEntry) do if compTemp then UnregistTriggerEvent(self, compTemp) end end self.__triggerEventEntry = nil end end end function UIBaseView:RegistDropEvent(comp,list) RegistDropEvent(self,comp,list) end function UIBaseView:RemoveTargetDropEvent(comp) RemoveTargetDropEvent(self,comp) end function UIBaseView:SetPushStyle(style) self.context = self.context or {} self.context.__pushStyle = style end function UIBaseView:OnCloseAndRecoverView(viewClassPath) if viewClassPath == self.__viewClassPath then self:CloseView(true) end end --当overWrite为false时 后面参数无意义 function UIBaseView:SetSortingLayer(overWrite, layerName, order) if GameAppInfo.IsVersionGreaterThan18000() then SetSortingLayer(self, overWrite, layerName, order) else local viewCanvas = self.gameObject:GetComponent(typeof(UnityEngine.Canvas)) if viewCanvas then if overWrite then viewCanvas.overrideSorting = true viewCanvas.sortingLayerName = layerName viewCanvas.sortingOrder = order else viewCanvas.overrideSorting = false end end end end local ViewMT = { __index = function(t, k) local v = rawget(t, k) if v == nil then local viewType = rawget(t, '__viewType') v = rawget(viewType, k) while v == nil do viewType = rawget(viewType, 'BaseViewType') if viewType then v = rawget(viewType, k) else break end end end return v end } local function CreateViewClass(baseType, classPath) local CreateViewObject = function(viewType, viewCanvas) local viewObj = { __viewType = viewType, __viewCanvas = viewCanvas, __viewClassPath = viewType.ViewClassPath, } return setmetatable(viewObj, ViewMT) end local viewType = { BaseViewType = baseType or UIBaseView, ViewClassPath = classPath, CreateViewObject = CreateViewObject, } return viewType end local function GetViewClass(classPath) --TODO 优化此处以减少字符串拼接的消耗,可考虑将运行过程中所有定义过的类型存储起来,提供快速查询获取接口 local viewClass = require('View/'..classPath) viewClass.ViewClassPath = classPath return viewClass end return { CreateViewClass = CreateViewClass, GetViewClass = GetViewClass, ViewEntryFunc = ViewEntryFunc, UIEventTriggerType = UIEventTriggerType, }