1 . UIBaseComponent.lua
--[[
-- UI组件基类:所有UI组件从这里继承
-- 说明:
-- 1、采用基于组件的设计方式,容器类负责管理和调度子组件,实现类似于Unity中挂载脚本的功能
-- 2、组件对应Unity原生的各种Component和Script,容器对应Unity原生的GameObject
-- 3、写逻辑时完全不需要关注脚本调度,在cs中脚本函数怎么调度的,这里就怎么调度,只是要注意接口变动,lua侧没有Get、Set访问器
-- 注意:
-- 1、Lua侧组件的名字并不总是和Unity侧组件名字同步,Lua侧组件名字会作为组件系统中组件的标识
-- 2、Lua侧组件名字会在组件创建时提取Unity侧组件名字,随后二者没有任何关联,Unity侧组件名字可以随便改
-- 3、虽然Unity侧组件名字随后可以随意改,但是不建议(有GC),此外Lua侧组件一旦创建,使用时全部以Lua侧名字为准
-- 4、虽然支持Update、LateUpdate、FixedUpdate更新,但是UI组件最好不要使用---不要定义这些函数即可
-- 5、需要定时刷新的界面,最好启用定时器、协程,界面需要刷新的频率一般较低,倒计时之类的只需要每秒钟更新一次即可
--]]
local UIBaseComponent = BaseClass("UIBaseComponent", Updatable)
local base = Updatable
-- 构造函数:除非特殊情况,所有子类不要再写这个函数,初始化工作放OnCreate
-- 多种重载方式:
-- 1、ComponentTypeClass.New(relative_path)
-- 2、ComponentTypeClass.New(child_index)
-- 3、ComponentTypeClass.New(unity_gameObject)
local function __init(self, holder, var_arg)
assert(not IsNull(holder), "Err : holder nil!")
assert(not IsNull(holder.transform), "Err : holder tansform nil!")
assert(not IsNull(var_arg), "Err: var_arg nil!")
-- 窗口view层脚本
self.view = nil
-- 持有者
self.holder = holder
-- 脚本绑定的transform
self.transform = nil
-- transform对应的gameObject
self.gameObject = nil
-- trasnform对应的RectTransform
self.rectTransform = nil
-- 名字:Unity中获取Transform的名字是有GC的,而Lua侧组件大量使用了名字,所以这里缓存下
self.__name = nil
-- 绑定数据:在某些场景下可以提供诸多便利
self.__bind_data = nil
-- 可变类型参数,用于重载
self.__var_arg = var_arg
-- 这里一定要等资源异步加载完毕才启用Update
self:EnableUpdate(false)
end
-- 析构函数:所有组件的子类不要再写这个函数,释放工作全部放到OnDestroy
local function __delete(self)
self:OnDestroy()
end
-- 创建
local function OnCreate(self)
assert(not IsNull(self.holder), "Err : holder nil!")
assert(not IsNull(self.holder.transform), "Err : holder tansform nil!")
-- 初始化view
if self._class_type == UILayer then
self.view = nil
else
local now_holder = self.holder
while not IsNull(now_holder) do
if now_holder._class_type == UILayer then
self.view = self
break
elseif not IsNull(now_holder.view) then
self.view = now_holder.view
break
end
now_holder = now_holder.holder
end
assert(not IsNull(self.view))
end
-- 初始化其它基本信息
if type(self.__var_arg) == "string" then
-- 与持有者的相对路径
self.transform = UIUtil.FindTrans(self.holder.transform, self.__var_arg)
self.gameObject = self.transform.gameObject
elseif type(self.__var_arg) == "number" then
-- 持有者第index个孩子
self.transform = UIUtil.GetChild(self.holder.transform, self.__var_arg)
self.gameObject = self.transform.gameObject
elseif type(self.__var_arg) == "userdata" then
-- Unity侧GameObject
self.gameObject = self.__var_arg
self.transform = gameObject.transform
else
error("OnCreate : error params list! "..type(self.__var_arg).." "..tostring(self.__var_arg))
end
self.__name = self.gameObject.name
self.rectTransform = UIUtil.FindComponent(self.transform, typeof(CS.UnityEngine.RectTransform))
self.__var_arg = nil
end
-- 打开
local function OnEnable(self)
-- 启用更新函数
self:EnableUpdate(true)
end
-- 获取名字
local function GetName(self)
return self.__name
end
-- 设置名字:toUnity指定是否同时设置Unity侧的名字---不建议,实在想不到什么情况下会用,但是调试模式强行设置,好调试
local function SetName(self, name, toUnity)
if self.holder.OnComponentSetName ~= nil then
self.holder:OnComponentSetName(self, name)
end
self.__name = name
if toUnity or Config.Debug then
if IsNull(self.gameObject) then
Logger.LogError("gameObject null, you maybe have to wait for loading prefab finished!")
return
end
self.gameObject.__name = name
end
end
-- 设置绑定数据
local function SetBindData(self, data)
self.__bind_data = data
end
-- 获取绑定数据
local function GetBindData(self)
return self.__bind_data
end
-- 激活、反激活
local function SetActive(self, active)
if active then
self.gameObject:SetActive(active)
self:OnEnable()
else
self:OnDisable()
self.gameObject:SetActive(active)
end
end
-- 获取激活状态
local function GetActive(self)
return self.gameObject.activeSelf
end
-- 等待资源准备完毕:用于协程
local function WaitForCreated(self)
coroutine.waituntil(function()
return not IsNull(self.gameObject)
end)
end
-- 关闭
local function OnDisable(self)
-- 禁用更新函数
self:EnableUpdate(false)
end
-- 销毁
local function OnDestroy(self)
if self.holder.OnComponentDestroy ~= nil then
self.holder:OnComponentDestroy(self)
end
self.holder = nil
self.transform = nil
self.gameObject = nil
self.rectTransform = nil
self.__name = nil
self.__bind_data = nil
end
UIBaseComponent.__init = __init
UIBaseComponent.__delete = __delete
UIBaseComponent.OnCreate = OnCreate
UIBaseComponent.OnEnable = OnEnable
UIBaseComponent.GetName = GetName
UIBaseComponent.SetName = SetName
UIBaseComponent.SetBindData = SetBindData
UIBaseComponent.GetBindData = GetBindData
UIBaseComponent.SetActive = SetActive
UIBaseComponent.GetActive = GetActive
UIBaseComponent.WaitForCreated = WaitForCreated
UIBaseComponent.OnDisable = OnDisable
UIBaseComponent.OnDestroy = OnDestroy
return UIBaseComponent
2 . UIBaseContainer.lua
--[[
-- UI容器基类:当一个UI组件持有其它UI组件时,它就是一个容器类,它要负责调度其它UI组件的相关函数
-- 注意:
-- 1、window.view是窗口最上层的容器类
-- 2、AddComponent用来添加组件,一般在window.view的OnCreate中使用,RemoveComponent相反
-- 3、GetComponent用来获取组件,GetComponents用来获取一个类别的组件
-- 4、很重要:子组件必须保证名字互斥,即一个不同的名字要保证对应于Unity中一个不同的Transform
--]]
local UIBaseContainer = BaseClass("UIBaseContainer", UIBaseComponent)
-- 基类,用来调用基类方法
local base = UIBaseComponent
-- 创建
local function OnCreate(self)
base.OnCreate(self)
self.components = {}
self.length = 0
end
-- 打开
local function OnEnable(self)
base.OnEnable(self)
self:Walk(function(component)
component:OnEnable()
end)
end
-- 遍历:注意,这里是无序的
local function Walk(self, callback, component_class)
for _,components in pairs(self.components) do
for cmp_class,component in pairs(components) do
if component_class == nil then
callback(component)
elseif cmp_class == component_class then
callback(component)
end
end
end
end
-- 如果必要,创建新的记录,对应Unity下一个Transform下所有挂载脚本的记录表
local function AddNewRecordIfNeeded(self, name)
if self.components[name] == nil then
self.components[name] = {}
end
end
-- 记录Component
local function RecordComponent(self, name, component_class, component)
-- 同一个Transform不能挂两个同类型的组件
assert(self.components[name][component_class] == nil, "Aready exist component_class : ", component_class.__cname)
self.components[name][component_class] = component
end
-- 子组件改名回调
local function OnComponentSetName(self, component, new_name)
AddNewRecordIfNeeded(self, new_name)
-- 该名字对应Unity的Transform下挂载的所有脚本都要改名
local old_name = component:GetName()
local components = self.components[old_name]
for k,v in pairs(components) do
v:SetName(new_name)
RecordComponent(self, new_name, k, v)
end
self.components[old_name] = nil
end
-- 子组件销毁
local function OnComponentDestroy(self, component)
self.length = self.length - 1
end
-- 添加组件
-- 多种重载方式
-- 1、直接添加Lua侧组件:inst:AddComponent(ComponentTypeClass, luaComponentInst)
-- 2、指定Lua侧组件类型和必要参数,新建组件并添加,多种重载方式:
-- A)inst:AddComponent(ComponentTypeClass, relative_path)
-- B)inst:AddComponent(ComponentTypeClass, child_index)
-- C)inst:AddComponent(ComponentTypeClass, unity_gameObject)
local function AddComponent(self, component_target, var_arg, ...)
assert(component_target.__ctype == ClassType.class)
local component_inst = nil
local component_class = nil
if type(var_arg) == "table" and var_arg.__ctype == ClassType.instance then
component_inst = var_arg
component_class = var_arg._class_type
else
component_inst = component_target.New(self, var_arg)
component_class = component_target
component_inst:OnCreate(...)
end
local name = component_inst:GetName()
AddNewRecordIfNeeded(self, name)
RecordComponent(self, name, component_class, component_inst)
self.length = self.length + 1
return component_inst
end
-- 获取组件
local function GetComponent(self, name, component_class)
local components = self.components[name]
if components == nil then
return nil
end
if component_class == nil then
-- 必须只有一个组件才能不指定类型,这一点由外部代码保证
assert(table.count(components) == 1, "Must specify component_class while there are more then one component!")
for _,component in pairs(components) do
return component
end
else
return components[component_class]
end
end
-- 获取一系列组件:2种重载方式
-- 1、获取一个类别的组件
-- 2、获取某个name(Transform)下的所有组件
local function GetComponents(self, component_target)
local components = {}
if type(component_target) == "table" then
self:Walk(function(component)
table.insert(component)
end, component_target)
elseif type(component_target) == "string" then
components = self.components[component_target]
else
error("GetComponents params err!")
end
return components
end
-- 获取组件个数
local function GetComponentsCount(self)
return self.length
end
-- 移除组件
local function RemoveComponent(self, name, component_class)
local component = self:GetComponent(name, component_class)
if component ~= nil then
local cmp_class = component._class_type
component:Delete()
self.components[name][cmp_class] = nil
end
end
-- 移除一系列组件:2种重载方式
-- 1、移除一个类别的组件
-- 2、移除某个name(Transform)下的所有组件
local function RemoveComponents(self, component_target)
local components = self:GetComponents(component_target)
for _,component in pairs(components) do
local cmp_name = component:GetName()
local cmp_class = component._class_type
component:Delete()
self.components[cmp_name][cmp_class] = nil
end
return components
end
-- 关闭
local function OnDisable(self)
base.OnDisable(self)
self:Walk(function(component)
component:OnDisable()
end)
end
-- 销毁
local function OnDestroy(self)
self:Walk(function(component)
-- 说明:现在一个组件可以被多个容器持有,但是holder只有一个,所以由holder去释放
if component.holder == self then
component:Delete()
end
end)
self.components = nil
base.OnDestroy(self)
end
UIBaseContainer.OnCreate = OnCreate
UIBaseContainer.OnEnable = OnEnable
UIBaseContainer.Walk = Walk
UIBaseContainer.OnComponentSetName = OnComponentSetName
UIBaseContainer.OnComponentDestroy = OnComponentDestroy
UIBaseContainer.AddComponent = AddComponent
UIBaseContainer.GetComponent = GetComponent
UIBaseContainer.GetComponents = GetComponents
UIBaseContainer.GetComponentsCount = GetComponentsCount
UIBaseContainer.RemoveComponent = RemoveComponent
UIBaseContainer.RemoveComponents = RemoveComponents
UIBaseContainer.OnDisable = OnDisable
UIBaseContainer.OnDestroy = OnDestroy
return UIBaseContainer
3 . UIBaseCtrl.lua
--[[
-- UI控制层基类:发送网络请求(网络数据)、操作游戏逻辑、修改模型数据(本地数据)
-- 注意:
-- 1、UI控制层用于衔接Model层和View层,主要是用来修改数据,或者进行游戏逻辑控制
-- 2、修改数据:界面操作相关数据直接写Model层、游戏逻辑相关数据写数据中心
-- 3、游戏控制:发送网络请求、调用游戏控制逻辑函数
-- 4、Ctrl层是无状态的,不能保存变量--调试模式下强制
--]]
local UIBaseCtrl = BaseClass("UIBaseCtrl")
local function __init(self, model)
assert(model ~= nil)
-- 强制不能直接写变量
if Config.Debug then
self.model = setmetatable({}, {
__index = model,
__newindex = function(tb, key, value)
if type(value) ~= "function" then
error("You can't save data here!", 2)
end
end
})
else
self.model = model
end
end
local function __delete(self)
self.model = nil
end
UIBaseCtrl.__init = __init
UIBaseCtrl.__delete = __delete
return UIBaseCtrl
4 . UIBaseModel.lua
--[[
-- UI模型层基类:该界面相关数据,同时负责消息定制
-- 注意:
-- 1、数据大体分为两类:游戏逻辑数据、界面控制数据
-- 2、游戏逻辑数据:从游戏数据中心取数据,这里不做为数据源,只做中转和必要处理(如排序)---游戏中心数据改动以后在这里监听变化
-- 3、界面控制数据:一般会影响到多个界面展示的控制数据,登陆界面显示当前服务器,当受到选服界面操作的影响
-- 4、界面Model层对View层是只读不写的,一定不要在View层写Model
-- 5、界面Model层不依赖Ctrl层和View层,意思是说拿掉这这两层代码,Model依旧能完好运行
-- 6、界面Model层数据只影响UI,不影响游戏逻辑,游戏逻辑不能从Model层取数据,意思是没有界面,游戏依旧能跑
--]]
local UIBaseModel = BaseClass("UIBaseModel")
-- 如非必要,别重写构造函数,使用OnCreate初始化
local function __init(self, ui_name)
-- 回调管理,使其最长保持和Model等同的生命周期
self.__ui_callback = {}
self.__data_callback = {}
self.__ui_name = ui_name
self:OnCreate()
end
-- 如非必要,别重写析构函数,使用OnDestroy销毁资源
local function __delete(self)
self:OnDestroy()
for k,v in pairs(self.__ui_callback) do
self:RemoveUIListener(k, v)
end
for k,v in pairs(self.__data_callback) do
self:RemoveDataListener(k, v)
end
self.__ui_callback = nil
self.__data_callback = nil
self.__ui_name = nil
end
-- 创建:变量定义,初始化,消息注册
-- 注意:窗口生命周期内保持的成员变量放这
local function OnCreate(self)
end
-- 打开:刷新数据模型
-- 注意:窗口关闭时可以清理的成员变量放这
local function OnEnable(self, ...)
end
-- 关闭
-- 注意:必须清理OnEnable中声明的变量
local function OnDisable(self)
end
-- 销毁
-- 注意:必须清理OnCreate中声明的变量
local function OnDestroy(self)
end
-- 注册消息
local function OnAddListener(self)
end
-- 注销消息
local function OnRemoveListener(self)
end
-- 激活:给UIManager用,别重写
local function Activate(self, ...)
self:OnAddListener()
self:OnEnable(...)
end
-- 反激活:给UIManager用,别重写
local function Deactivate(self)
self:OnRemoveListener()
self:OnDisable()
end
local function AddCallback(keeper, msg_name, callback)
assert(callback ~= nil)
keeper[msg_name] = callback
end
local function GetCallback(keeper, msg_name)
return keeper[msg_name]
end
local function RemoveCallback(keeper, msg_name, callback)
assert(callback ~= nil)
keeper[msg_name] = nil
end
-- 注册UI数据监听事件,别重写
local function AddUIListener(self, msg_name, callback)
local bindFunc = Bind(self, callback)
AddCallback(self.__ui_callback, msg_name, bindFunc)
UIManager:GetInstance():AddListener(msg_name, bindFunc)
end
-- 发送UI数据变动事件,别重写
local function UIBroadcast(self, msg_name, ...)
UIManager:GetInstance():Broadcast(msg_name, ...)
end
-- 注销UI数据监听事件,别重写
local function RemoveUIListener(self, msg_name, callback)
local bindFunc = GetCallback(self.__ui_callback, msg_name)
RemoveCallback(self.__ui_callback, msg_name, bindFunc)
UIManager:GetInstance():RemoveListener(msg_name, bindFunc)
end
-- 注册游戏数据监听事件,别重写
local function AddDataListener(self, msg_name, callback)
local bindFunc = Bind(self, callback)
AddCallback(self.__data_callback, msg_name, bindFunc)
DataManager:GetInstance():AddListener(msg_name, bindFunc)
end
-- 注销游戏数据监听事件,别重写
local function RemoveDataListener(self, msg_name, callback)
local bindFunc = GetCallback(self.__data_callback, msg_name)
RemoveCallback(self.__data_callback, msg_name, bindFunc)
DataManager:GetInstance():RemoveListener(msg_name, bindFunc)
end
UIBaseModel.__init = __init
UIBaseModel.__delete = __delete
UIBaseModel.OnCreate = OnCreate
UIBaseModel.OnEnable = OnEnable
UIBaseModel.OnDisable = OnDisable
UIBaseModel.OnDestroy = OnDestroy
UIBaseModel.OnAddListener = OnAddListener
UIBaseModel.OnRemoveListener = OnRemoveListener
UIBaseModel.Activate = Activate
UIBaseModel.Deactivate = Deactivate
UIBaseModel.AddUIListener = AddUIListener
UIBaseModel.UIBroadcast = UIBroadcast
UIBaseModel.RemoveUIListener = RemoveUIListener
UIBaseModel.AddDataListener = AddDataListener
UIBaseModel.RemoveDataListener = RemoveDataListener
return UIBaseModel
5 . UIBaseRecordModel.lua
--[[
-- UI带有子窗口记忆功能的模型层基类:窗口被重新打开时会自动打开之前没有关闭的子级窗口
--]]
local UIBaseRecordModel = BaseClass("UIBaseRecordModel", UIBaseModel)
local base = UIBaseModel
-- 创建
local function OnCreate(self)
base.OnCreate(self)
-- 子级窗口栈
self.__window_stack = {}
-- 是否启用记录
self.__enable_record = false
-- 保持Model
UIManager:GetInstance():SetKeepModel(self.__ui_name, true)
end
-- 打开
local function OnEnable(self, ...)
base.OnEnable(self, ...)
-- 重新打开上次保留的窗口
table.walk(self.__window_stack, function(index, ui_name)
UIManager:GetInstance():OpenWindow(ui_name)
end)
self.__enable_record = true
end
-- 获取栈
local function GetWindowStack(self)
return self.__window_stack
end
-- 清空栈
local function ClearWindowStack(self)
self.__window_stack = {}
end
-- 子级窗口入栈
local function OnWindowOpen(self, window)
if not self.__enable_record or window.Layer:GetName() ~= UILayers.NormalLayer.Name then
return
end
table.insert(self.__window_stack, window.Name)
-- 保持Model
UIManager:GetInstance():SetKeepModel(window.Name, true)
end
-- 出栈
local function OnWindowClose(self, window)
if not self.__enable_record or window.Layer:GetName() ~= UILayers.NormalLayer.Name then
return
end
local index = nil
for i,v in pairs(self.__window_stack) do
if v == window.Name then
index = i
break
end
end
if index then
local length = table.length(self.__window_stack)
for i = 0, length - index do
local ui_name = table.remove(self.__window_stack, length - i)
-- 取消保持Model
UIManager:GetInstance():SetKeepModel(ui_name, false)
end
end
end
-- 注册消息
local function OnAddListener(self)
base.OnAddListener(self)
self:AddUIListener(UIMessageNames.UIFRAME_ON_WINDOW_OPEN, OnWindowOpen)
self:AddUIListener(UIMessageNames.UIFRAME_ON_WINDOW_CLOSE, OnWindowClose)
end
-- 注销消息
local function OnRemoveListener(self)
base.OnRemoveListener(self)
self:RemoveUIListener(UIMessageNames.UIFRAME_ON_WINDOW_OPEN, OnWindowOpen)
self:RemoveUIListener(UIMessageNames.UIFRAME_ON_WINDOW_CLOSE, OnWindowClose)
end
-- 关闭
local function OnDisable(self)
base.OnDisable(self)
self.__enable_record = false
end
-- 销毁
local function OnDestroy(self)
self.__window_stack = nil
base.OnDestroy(self)
end
UIBaseRecordModel.OnCreate = OnCreate
UIBaseRecordModel.OnEnable = OnEnable
UIBaseRecordModel.GetWindowStack = GetWindowStack
UIBaseRecordModel.ClearWindowStack = ClearWindowStack
UIBaseRecordModel.OnAddListener = OnAddListener
UIBaseRecordModel.OnRemoveListener = OnRemoveListener
UIBaseRecordModel.OnDisable = OnDisable
UIBaseRecordModel.OnDestroy = OnDestroy
return UIBaseRecordModel
6 . UIBaseView.lua
--[[
-- UI视图层基类:该界面所有UI刷新操作,只和展示相关的数据放在这,只有操作相关数据放Model去
-- 注意:
-- 1、被动刷新:所有界面刷新通过消息驱动---除了打开界面时的刷新
-- 2、对Model层可读,不可写---调试模式下强制
-- 3、所有写数据、游戏控制操作、网络相关操作全部放Ctrl层
-- 4、Ctrl层不依赖View层,但是依赖Model层
-- 5、任何情况下不要在游戏逻辑代码操作界面刷新---除了打开、关闭界面
--]]
local UIBaseView = BaseClass("UIBaseView", UIBaseContainer)
local base = UIBaseContainer
-- 构造函数:必须把基类需要的所有参数列齐---即使在这里不用,提高代码可读性
-- 子类别再写构造函数,初始化工作放OnCreate
local function __init(self, holder, var_arg, model, ctrl)
assert(model ~= nil)
assert(ctrl ~= nil)
self.ctrl = ctrl
-- 强制不能直接写Model层
if Config.Debug then
self.model = setmetatable({}, {
__index = model,
__newindex = function(tb, key, value)
error("You can't write model derectly!", 2)
end
})
else
self.model = model
end
-- 窗口画布
self.canvas = nil
-- 窗口基础order,窗口内添加的其它canvas设置的order都以它做偏移
self.base_order = 0
end
-- 创建:资源加载完毕
local function OnCreate(self)
base.OnCreate(self)
-- 窗口画布
self.canvas = self:AddComponent(UICanvas, "", 0)
-- 回调管理,使其最长保持和View等同的生命周期
self.__ui_callback = {}
-- 初始化RectTransform
self.rectTransform.offsetMax = Vector2.zero
self.rectTransform.offsetMin = Vector2.zero
self.rectTransform.localScale = Vector3.one
self.rectTransform.localPosition = Vector3.zero
end
-- 打开:窗口显示
local function OnEnable(self)
self.base_order = self.holder:PopWindowOder()
base.OnEnable(self)
self:OnAddListener()
end
-- 注册消息
local function OnAddListener(self)
end
-- 注销消息
local function OnRemoveListener(self)
end
local function AddCallback(keeper, msg_name, callback)
assert(callback ~= nil)
keeper[msg_name] = callback
end
local function GetCallback(keeper, msg_name)
return keeper[msg_name]
end
local function RemoveCallback(keeper, msg_name, callback)
assert(callback ~= nil)
keeper[msg_name] = nil
end
-- 注册UI数据监听事件,别重写
local function AddUIListener(self, msg_name, callback)
local bindFunc = Bind(self, callback)
AddCallback(self.__ui_callback, msg_name, bindFunc)
UIManager:GetInstance():AddListener(msg_name, bindFunc)
end
-- 注销UI数据监听事件,别重写
local function RemoveUIListener(self, msg_name, callback)
local bindFunc = GetCallback(self.__ui_callback, msg_name)
RemoveCallback(self.__ui_callback, msg_name, bindFunc)
UIManager:GetInstance():RemoveListener(msg_name, bindFunc)
end
-- 关闭:窗口隐藏
local function OnDisable(self)
self:OnRemoveListener()
base.OnDisable(self)
self.holder:PushWindowOrder()
end
-- 销毁:窗口销毁
local function OnDestroy(self)
for k,v in pairs(self.__ui_callback) do
self:RemoveUIListener(k, v)
end
self.model = nil
self.ctrl = nil
self.__ui_callback = nil
base.OnDestroy(self)
end
UIBaseView.__init = __init
UIBaseView.OnCreate = OnCreate
UIBaseView.OnEnable = OnEnable
UIBaseView.OnAddListener = OnAddListener
UIBaseView.OnRemoveListener = OnRemoveListener
UIBaseView.OnDisable = OnDisable
UIBaseView.AddUIListener = AddUIListener
UIBaseView.RemoveUIListener = RemoveUIListener
UIBaseView.OnDestroy = OnDestroy
return UIBaseView