UI编码指南

UI编码指南

kun

2015.11.24

设计思想

界面逻辑采用MVC设计思想。在实践过程中,舍弃MVC对重用部分的理解,只使用对业务责任划分的理解。

 

核心概念:Module

在我们的代码里,各种各样的Manager就是Module。这些M 负责数据的加载、保存、更新、删除等一系列偏向数据层的操作。M的数据来源一般来自于和服务器通讯。我们的Module 既有“使用GameEvents 系统来做数据推送通知”,也有Controller层通过自身Tick、OnLoaded、OnShowImpl这些时机函数自发的拉取数据。需要根据具体情况来进行选择。

 

核心概念:Controller

代码里的UIController及其子类就是Controller。这些C的责任有三个方向:

1、对数据层来说(上层),Controller是数据层的用户,负责实现“逻辑行为如何使用数据层”这个事情。这可能是一个行为的表达(一个函数,被动的等人调用),也可能是一个时机的表达(注册一个事件,等待时机推送)。

2、对Window层来说(下层),Controller是将逻辑数据“转换”成Window理解的数据。(比如“角色的名字”是一个数据层概念,对于Window来说,应该是Label_Name的Text字段)。

3、对Controller层来说(同级),是一个不同业务之间有关联的逻辑的互相调用。

 

核心概念:Window

代码里的UIWindow 及其子类就是Window。这些W负责GUI的具体显示任务。主要是对控件的操作功能封装、一些界面内在的显示逻辑(动画啊,不同的SubControl的显示逻辑、位置操作、颜色操作等)。最重要的责任之一是提供界面元素的控制接口。另外一个重要的责任是负责向系统反馈用户的交互输入(事件)。

 

(接下来要谈的事情,仅代表我的看法)

深入理解Controller的责任很重要,因为它处于一个承上启下的角色。

常见的误区在于对数据层的直接访问跳过了Controller层,直接写在Window层的代码里了。

比如“点击按钮就改变角色外形”这个例子:

改变模型的能力由生物表达层Character来提供,外形和模型的对照关系由CharacterData提供。点击按钮这个事件由Window层提供,而“点击按钮修改CharacterData的数据”这件事情,便是Controller的责任,Controller负责衔接两个不同层次之间的交互。

如果没有Controller层,直接将逻辑写在Window的OnClickButton函数里,可不可以?

从结果上讲,没有错误。

从设计上讲,将逻辑数据和Window控件的关联性强加给了Window.

从自身的特性上讲,Window本身是具有资源的对象,势必参与资源管理活动(加载时机、卸载时机等),数据层自己也有数据的拉取、更新这些和时机相关的事情。而Controller是一个纯粹的内存对象,封装的也只是操作逻辑,自身是没有时机相关的事情的。这个“不变”,让Controller很适合做两个层次的中继者这个角色。

目录结构

LuaScripts/Client  放Module层的地方,各种Manager

LuaScripts/Client/UI 放 Controller 和 Window 的地方。我们将V和C放一起.

LuaScripts/UIEngineUIEngine中关于 Window 和 Controller 的各种重要基类,必看。

阅读代码前的必备知识

1、  UIController在我们的代码里,是每类型唯一。只应该通过UIControllerManager来获取和销毁。(注意和单件的区别,单件在程序运行时是不销毁的)。

2、  除了UIController里直接使用UIWindow,代码其他任何地方不操作Window.所以对Window资源的管理,都通过对Controller的创建和销毁来完成。

3、  由于Window加载有时间,而Controller是按需立即创建,在Window加载完成之前,Controller是可能收到一些数据变化的通知的,由于这些时机是瞬时的,所以等Window创建好,早就错过了更新自身状态的时机。尤其是采用Controller向Window推送数据这种实现时,处理这种不同步尤为重要(Window主动拉取数据的话会自动刷新)。为此Controller有一个 _onSyncContent 接口,用来规定一次强制的Controller和Window的同步。

4、  还是由于Window的创建有时间,Controller内部需要在任何使用Window的时候都小心判断_window是否不为空。(甚至在一些特定的开发过程中,Window都可以不存在,我们只在Controller里打Print就可以搞定逻辑层的事情)

5、  有一部分Window/Controller代码是在C#里的,不是全部都在Lua里。这是历史遗留。

6、  为了避免内存和加载的峰值,我们采用“按需加载”这个大原则,如无必要不加载。但是请谨慎的处理销毁时机,不要遗忘了。

7、  按需加载使用UIControllerManager的LoadOrShowController接口,这个函数接受的回调参数是onCreate,不是onShow,请注意不要被坑了。这只是一个语法糖式的便捷接口。

8、  Window Layer Management 策略参考了Mac OS。这里有一篇介绍性的文章

http://blog.csdn.net/kun1234567/article/details/47783681

9、  由于Lua的特性,我们在模拟函数重载时,有一个特定写法,原理可以阅读Class.lua。例子如下:

 

 

继承

local X = UIWindow:extend

{

    --静态变量放置区

}

 

 

构造函数

function X:__init(gameObject, controller)

      ------注意这里必须是直接父类(不能是祖先类)

      -------必须是点,不能是冒号调用

      -------必须传递self.

           UIWindow.__init(self,gameObject, controller)

end

 

析构函数

function X:__release()

--- release your self

--- base type relase

---也是点,也是直接父类,也是self!

UIWindow.release(self)

end

 

 

核心类

UIControl (不是Controller,请仔细看)

控件的基类,负责在所有层面上都通用的操作的表达,比如visible。Window也可以视为一种特殊的Control

 

UIWindowBase

UIWindow

Window概念的表达,负责一些基于窗口的行为的表达。也提供获取子控件_getControl、_onShow、_onHide这些必备功能。

 

UIWindowManager

主要是管理窗口资源的加载、卸载事务。

 

UIController

Controller的基类,本身没啥特别的。请注意和window创建相关的代码,这些代码揭示了两者的协作关系和声明周期关系。

 

UIControllerManager

Controller 的创建和销毁

 

UIControllerLevel

Layer Management相关.我们使用一个类似栈的结构,略有不同。参见LinkedList。

历史原因类

UICSController

UICSWindow

 

这是为了在Lua里也能从一定程度上控制c#的Window和Controller而设计的。是妥协出来的代码。

 

结束

请注意,

1、  上述类的操作接口请确定自己掌握了,包括一些通过 callInterface 来进行模拟virtual 函数的地方,这些都是充分控制Window和Controller的关键。

2、  就算你没仔细看这些代码,也请一定要看前面的阅读代码前的必备知识,无数先烈在这些概念上被坑过。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值