小眼游戏架构:UI篇:三层架构(UI层)
上一篇我们分析了UI的架构原则以及为什么要这么架构的一些原因,这篇会具体实现架构的方方面面,东西会有点多。我辈求道,岂能求快!
为了避免框架的干扰我们先来配置一下开发环境。
LuaFrameWork的启动是在:
加载的相关可以看这里(加载)
上面主要做的就是去除和我们现在没有联系的模块,避免一些问题。
现在开始分析具体流程。
经过前一篇的分析我们可以总结出:
UI管理层(UIManager):加载、打开、关闭、卸载。管理UI集合的自动打开和关闭,以及对外的接口。
UI集合层(UIBaseCollect):加载、打开、关闭、卸载。管理多个UI。
UI层(UIBaseView):加载、打开、关闭、卸载。管理UI本身的生命周期。
其实流程都是类似的,一层层的管理下去。
流程总览
上面的图是我们的三层架构流程总览图。
按列划分:
第一列:UI管理层(UIManager)相关操作;
第二列:UI集合层(UIBaseColelct)相关操作;
第三列:UI层(UIBaseView)相关操作;
实现代表同步,虚线代表异步(不在同一帧执行)。
我们采取自下而上的讲解方式。那么先开始UI层吧。
UI层
一般的UI流程肯定是有以下流程:加载、打开、关闭、卸载。
在分析详细四个流程前,我们先确认下Prefab的制作规范,这样对于讲解后面的流程是有帮助的。
Prefab的制作要求:
上图有两个部分:编辑器模式下的Prefab显示,和运行时的Prefab显示
这样一对比会发现这两个图有点对不上,是的,运行时和编辑器模式下的显示不是一样的。
- 先看编辑器模式:
绿色是UIRoot,黄色是UI相机,红色是Prefab的主题结构。 - 再看运行时部分:
红色是代表UIRoot,绿色代表Prefab的主题就够。
因为整个UI使用一个UIRoot和一个UI相机,但是现在每个UI都有一个UIRoot和一个相机,所以我们将这两个部分抽离出来形成"ui/prefab/uibase"结构,这个节点将会是所有UI的父节点。后续UI在加载后会将Prefab下Core节点改名成"ui/prefab/uipanel_messagebox"放到UIRoot(“ui/prefab/uipanel_base”)下面去;
好了Prefab的制作规范就完成了。
下图是代码解释:加载完成Prefab之后实例化过程。
public static GameObject InitGameObject(int type, GameObject obj, string assetName)
{......// UIelse if(type == 2){GameObject root = GameObject.Find("ui/prefab/uipanel_base");parent = root.transform;son = obj.transform.FindChild("Core");GameObject.Destroy(obj);}......
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
现在来说UI的四个流程
UI加载
先看图
- 打开参数:有时候我们打开一个UI需要特定的一些数据去做显示,比如:UI上有多个页签,我现在想打开UI前就决定显示到哪个页签。我们经常会自己写一个管理器去管理UI的行为,这并没有问题,但是有时候我们会将数据放到管理器中,然后UI调用管理器中的数据,这样的设计并不好,与UI相关的数据最好通过参数的形式传进去,这就是我们打开参数设置的目的。
- 加载prefab是异步的:所以需要注意异步的问题,卸载的时候,在请求加载中需要取消加载。
- 绑定控件:这时一种省时省力的做法,后面会有单独的一个章节来讲解,这里就不说了。
- 注册UI事件 :UI的监听事件不会动态的改变,所以放在加载里面注册就可以了。我们处理事件的方式是:只有显示的UI才能收到监听事件的回调。你可能会问不显示的UI就收不到?是的,因为UI在显示时会重新刷新页面,所以就不需要在隐藏的时候更新了。
- 加载完成:加载完成之后会通知子类,这样子类就能知道加载已经完成,可以开始自己的操作了。
事件设计
既然UI上用到了事件注册,那我们就来说说事件的设计。
--[[注册消息,发送消息
--]]
local Message = {};-- 消息体
function BeginMessage(msgName)local msg = {};msg.name = msgName;return msg;
end-- 发送消息
function SendMessage(msg)DispatchMessage(msg);
end-- 注册消息
function RegisterMessage(msgName,tCall,t)if not Message[msgName] then Message[msgName] = {};endlocal inIndex = table.ContainValue(Message[msgName],tCall,"tCall");if inIndex ~= 0 thenreturn;endlocal msg = {};msg.t = t;msg.tCall = tCall;table.insert(Message[msgName],msg);
end-- 删除消息
function RemoveMessage(msgName,call)if not Message[msgName] then return;endlocal inIndex = table.ContainValue(Message[msgName],call,"tCall");if inIndex ~= 0 thentable.remove(Message[msgName],inIndex);end
end-- 触发注册消息
function DispatchMessage(msg)local registers = Message[msg.name];if not registers then return;endfor i,v in ipairs(registers) dov.tCall(v.t,msg);end
end
事件的流程比较简单,lua就中这点好,包罗万象,所以事件的实现方式简单。
UI打开
先看图
- 计算UI层级:想让UI呈现出前后的关系,我们需要改变UIPanel的depth值,我们在制作Prefab的过程中也会把UIPanel当成一个页面的容器。
- 最后显示的Prafab层级是最高的。
-- 设置UI层级
function _M:SetUILayer()local obj = GetGameObjectById(self.uiInstanceId);if not obj then print("SetUILayer is error " , self.name);return;end-- 获取一个层级,这个层级是目前最大的local layer = UILayer:CalculateLayer(self);self:AddUILayerHelper(layer);
end
-- 删除UI层级
function _M:DelUILayer()local obj = GetGameObjectById(self.uiInstanceId);if not obj then print("SetUILayer is error " , self.name);return;endlocal layer = UILayer:DelLayer(self);self:AddUILayerHelper(-layer);
end
function _M:AddUILayerHelper(layer)local obj = GetGameObjectById(self.uiInstanceId);if not obj then print("AddUILayerHelper is error " .. self.name);return;endlocal addLayer = layer * 100;local panels = CommonUtil.GetUIPanels(obj);-- C#中的用法 在lua中显得很另类for i = 0, panels.Length - 1 dopanels[i].depth = panels[i].depth + addLayer;end
end
实际上就是寻找整个Preafab的UIPanel然后全部加上一个值,这个值是计算出来的,用来保证当前显示的Prefab的UIPanel的depth是最大的,计算的方法是写在UILayer里面:保存一个当前UI对应的列表,每次打开UI的时候就去找到最后打开的一个然后+1。
UILayer设计如下:
3. atals的加载:这里的atlas包括图集、图片。Prefab包括:自身的序列化信息和引用的信息。Prefab本身只是序列化数据,不大,但是每次加载解析却浪费了时间,尤其是Prefab的结构越复杂,需要的时间就越多。既然Prefab本身不大那我们保证Prefab在不切换场景前不卸载,只卸载绑定在Prefab上的图集和图片,这样内存也没有增加多少,再次打开这个界面的时候会很快。
4. 显示完成:Prefab显示之后会通知子类,Prefab已经显示完成,可以开始自己的操作了。自己的操作:根据数据刷新页面显示。
UI关闭
先看图
关闭UI的流程和打开UI的流程刚还是相反的,所以就不说了。
UI卸载
卸载UI流程和加载UI流程也是相反的,所以就不说了。
Lua类的设计:
既然我们采取类的模式,那么lua得提供类的功能,lua实现类的逻辑很巧妙,lua的table中有一个重要特性,可以给当前的table设置一个元表(也是一个table),这样在当前table中找不到的属性和方法可以去元表table中去寻找,这个机制不就和类的方式是类似的么?这样就能轻松实现类了。
基类UIBaseVIew设计:
创建一个UIBaseView基类(所有UI的父类),ctor是构造函数。
使用者的子类设计:
UIPanel_MessageBox继承自UIBaseView,这样UIPanel_MessageBox也就拥有和UIBaseView一样的生命周期。
这样我们UI层(UIBaseView)就设计完成了。
项目地址:https://github.com/xiaoyanxiansheng/SmallEyeGame
下一篇:UI集合层
小眼游戏架构:UI篇:三层架构(UI层)相关推荐
- 项目架构之传统三层架构和领域模型三层架构
一.架构之传统三层架构 传统三层架构是一种软件架构,是一种典型的.基于贫血模型的.面向过程的JavaWeb分层方式.该架构分为以下三个层次: 数据访问层(DAL - Data Access Layer ...
- MyBatis学习:简单认识一下MVC架构模式和三层架构
1.本篇博客的背景和目的 目前我本人正在学习MyBatis框架,在原先了解并且懵懵懂懂使用的基础上,开始系统正式的学习.本篇博客阐述一下MVC架构模式和三层架构,以及明晰一下我们通常在Web项目中的编 ...
- JavaEE架构之传统三层架构,集群架构,分布式架构,微服务架构
javaEE架构 1.传统三层架构(all in one项目) 传统三层架构大致可以分为表现层,业务层和持久层(数据访问层).其中表现层负责接受请求和转发请求.业务层负责处理请求(注:事务管理,日志记 ...
- iOS开发UI篇—APP主流UI框架结构
iOS开发UI篇-APP主流UI框架结构 一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果: 二.搭建过程和 ...
- 第六章节 三层架构(一. 三层架构的概述)
一. 三层架构的概述 1.在大中型ASP.NET站点的设计开发中,通常采用三层架构的设计,既表现层.业务逻辑层.数据访问层,各层特点简述如下: 层级 说明 表现层 (UI) 用于显示数据和接收用户输入 ...
- 系统架构:经典三层架构
引言 经典三层架构是分层架构中最原始最典型的分层模式,其他分层架构都是其变种或扩展,例如阿里的四层架构模式和DDD领域驱动模型.阿里的 四层架构模型在三层基础上增加了 Manager 层,从而形成变种 ...
- java ssh三层架构_SSH和三层架构的MVC模式的对应关系
1.MVC(Model-View-Controller)设计模式: 首先让我们了解下MVC(Model-View-Controller)的概念: MVC全名是Model View Controller ...
- java ee 三层架构_JavaEE的三层架构
## JavaEE的三层架构 ## 1.JavaEE架构图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM ...
- JavaWeb三层架构的理解/三层架构的优缺点/三层架构与MVC的区别
1.三层架构 我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器.在JavaEE开发中,几乎全都是基于B/S架构的开发.那么在B/S架构 ...
最新文章
- 玩转Excel系列-SUMIFS函数使用及实例
- JAVA跟MYSQL数据库交互_【编写Java程序实现与Mysql数据库的连接,并交互性的实现简单查询,删除,修改,排序,显示等操作】...
- android R编译Super镜像时报错问题分析和定位
- kettle清洗mysql数据_ETL工具Kettle使用以及与Java整合实现数据清洗
- 【shell 练习5】编写简单的多级菜单
- 鲁大师2014 v3.75.14.1058 官方版
- 树莓派怎么切换输入法_树莓派如何安装中文输入法
- python相减函数subs,SUBS(subs是什么函数)
- 因式分解用python写程序_使用Python实现质因式分解算法
- unity 制作的app发布到andriod手机
- GICv3软件overview手册之GICv4对虚拟LPI的直接注入(1)
- doNet面试宝典-常见整理(重复率高)
- 智能型炉温测试仪kic x5软件,KIC X5 炉温测试仪产品说明ppt课件
- RAID 容量计算器
- b站python直播批量发送弹幕_Python实现自动发送B站直播弹幕软件
- 找谷歌地图上任意点的经纬度
- 传输层 TCP 拥塞控制(3):快速重传与快速恢复
- 4.贪心算法 含例题
- 前端实习生应该掌握什么技能?
- [人力资源机器]19关倒计时-攻略
热门文章
- Linux内核编译及系统裁剪
- Neo4j通过excel导入实体及关系时总是显示no changes,no records
- 电影制作的“文艺复兴”-你准备好了吗?
- HTC VIVE 基础开发1
- 实用的程序员面试技巧
- 真实项目之【邀请码活动模块】实现思路
- 《大象 Thinking in UML》学习笔记(十)——需求分析
- vscode Nuget Package Manager 提示 Versioning information could not be retrieved from the NuGet package
- 从开发人员走向架构师三步曲
- 基于Vshare插件实现vue分享功能