上一篇我们分析了UI的架构原则以及为什么要这么架构的一些原因,这篇会具体实现架构的方方面面,东西会有点多。我辈求道,岂能求快!

为了避免框架的干扰我们先来配置一下开发环境。
LuaFrameWork的启动是在:

加载的相关可以看这里(加载)
上面主要做的就是去除和我们现在没有联系的模块,避免一些问题。


现在开始分析具体流程。
经过前一篇的分析我们可以总结出:
UI管理层UIManager):加载、打开、关闭、卸载。管理UI集合的自动打开和关闭,以及对外的接口。
UI集合层UIBaseCollect):加载、打开、关闭、卸载。管理多个UI
UI层UIBaseView):加载、打开、关闭、卸载。管理UI本身的生命周期。
其实流程都是类似的,一层层的管理下去。

流程总览

上面的图是我们的三层架构流程总览图。
按列划分:
第一列:UI管理层UIManager)相关操作;
第二列:UI集合层UIBaseColelct)相关操作;
第三列:UI层UIBaseView)相关操作;
实现代表同步,虚线代表异步(不在同一帧执行)。

我们采取自下而上的讲解方式。那么先开始UI层吧。

UI层

一般的UI流程肯定是有以下流程:加载、打开、关闭、卸载
在分析详细四个流程前,我们先确认下Prefab的制作规范,这样对于讲解后面的流程是有帮助的。
Prefab的制作要求:
上图有两个部分:编辑器模式下的Prefab显示,和运行时的Prefab显示
这样一对比会发现这两个图有点对不上,是的,运行时和编辑器模式下的显示不是一样的。

  1. 先看编辑器模式
    绿色是UIRoot,黄色是UI相机,红色是Prefab的主题结构。
  2. 再看运行时部分
    红色是代表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加载

先看图

  1. 打开参数:有时候我们打开一个UI需要特定的一些数据去做显示,比如:UI上有多个页签,我现在想打开UI前就决定显示到哪个页签。我们经常会自己写一个管理器去管理UI的行为,这并没有问题,但是有时候我们会将数据放到管理器中,然后UI调用管理器中的数据,这样的设计并不好,与UI相关的数据最好通过参数的形式传进去,这就是我们打开参数设置的目的。
  2. 加载prefab是异步的:所以需要注意异步的问题,卸载的时候,在请求加载中需要取消加载。
  3. 绑定控件:这时一种省时省力的做法,后面会有单独的一个章节来讲解,这里就不说了。
  4. 注册UI事件 :UI的监听事件不会动态的改变,所以放在加载里面注册就可以了。我们处理事件的方式是:只有显示的UI才能收到监听事件的回调。你可能会问不显示的UI就收不到?是的,因为UI在显示时会重新刷新页面,所以就不需要在隐藏的时候更新了。
  5. 加载完成:加载完成之后会通知子类,这样子类就能知道加载已经完成,可以开始自己的操作了。

事件设计

既然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打开

先看图

  1. 计算UI层级:想让UI呈现出前后的关系,我们需要改变UIPaneldepth值,我们在制作Prefab的过程中也会把UIPanel当成一个页面的容器。
  2. 最后显示的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

实际上就是寻找整个PreafabUIPanel然后全部加上一个值,这个值是计算出来的,用来保证当前显示的PrefabUIPaneldepth是最大的,计算的方法是写在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实现类的逻辑很巧妙,luatable中有一个重要特性,可以给当前的table设置一个元表(也是一个table),这样在当前table中找不到的属性方法可以去元表table中去寻找,这个机制不就和类的方式是类似的么?这样就能轻松实现类了。

基类UIBaseVIew设计:


创建一个UIBaseView基类(所有UI的父类),ctor是构造函数。

使用者的子类设计:


UIPanel_MessageBox继承自UIBaseView,这样UIPanel_MessageBox也就拥有和UIBaseView一样的生命周期。

这样我们UI层UIBaseView)就设计完成了。

项目地址:https://github.com/xiaoyanxiansheng/SmallEyeGame

下一篇:UI集合层

小眼游戏架构:UI篇:三层架构(UI层)相关推荐

  1. 项目架构之传统三层架构和领域模型三层架构

    一.架构之传统三层架构 传统三层架构是一种软件架构,是一种典型的.基于贫血模型的.面向过程的JavaWeb分层方式.该架构分为以下三个层次: 数据访问层(DAL - Data Access Layer ...

  2. MyBatis学习:简单认识一下MVC架构模式和三层架构

    1.本篇博客的背景和目的 目前我本人正在学习MyBatis框架,在原先了解并且懵懵懂懂使用的基础上,开始系统正式的学习.本篇博客阐述一下MVC架构模式和三层架构,以及明晰一下我们通常在Web项目中的编 ...

  3. JavaEE架构之传统三层架构,集群架构,分布式架构,微服务架构

    javaEE架构 1.传统三层架构(all in one项目) 传统三层架构大致可以分为表现层,业务层和持久层(数据访问层).其中表现层负责接受请求和转发请求.业务层负责处理请求(注:事务管理,日志记 ...

  4. iOS开发UI篇—APP主流UI框架结构

    iOS开发UI篇-APP主流UI框架结构 一.简单示例 说明:使用APP主流UI框架结构完成简单的界面搭建 搭建页面效果:                                二.搭建过程和 ...

  5. 第六章节 三层架构(一. 三层架构的概述)

    一. 三层架构的概述 1.在大中型ASP.NET站点的设计开发中,通常采用三层架构的设计,既表现层.业务逻辑层.数据访问层,各层特点简述如下: 层级 说明 表现层 (UI) 用于显示数据和接收用户输入 ...

  6. 系统架构:经典三层架构

    引言 经典三层架构是分层架构中最原始最典型的分层模式,其他分层架构都是其变种或扩展,例如阿里的四层架构模式和DDD领域驱动模型.阿里的 四层架构模型在三层基础上增加了 Manager 层,从而形成变种 ...

  7. java ssh三层架构_SSH和三层架构的MVC模式的对应关系

    1.MVC(Model-View-Controller)设计模式: 首先让我们了解下MVC(Model-View-Controller)的概念: MVC全名是Model View Controller ...

  8. java ee 三层架构_JavaEE的三层架构

    ## JavaEE的三层架构 ## 1.JavaEE架构图 ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM ...

  9. JavaWeb三层架构的理解/三层架构的优缺点/三层架构与MVC的区别

    1.三层架构 我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器.在JavaEE开发中,几乎全都是基于B/S架构的开发.那么在B/S架构 ...

最新文章

  1. 玩转Excel系列-SUMIFS函数使用及实例
  2. JAVA跟MYSQL数据库交互_【编写Java程序实现与Mysql数据库的连接,并交互性的实现简单查询,删除,修改,排序,显示等操作】...
  3. android R编译Super镜像时报错问题分析和定位
  4. kettle清洗mysql数据_ETL工具Kettle使用以及与Java整合实现数据清洗
  5. 【shell 练习5】编写简单的多级菜单
  6. 鲁大师2014 v3.75.14.1058 官方版
  7. 树莓派怎么切换输入法_树莓派如何安装中文输入法
  8. python相减函数subs,SUBS(subs是什么函数)
  9. 因式分解用python写程序_使用Python实现质因式分解算法
  10. unity 制作的app发布到andriod手机
  11. GICv3软件overview手册之GICv4对虚拟LPI的直接注入(1)
  12. doNet面试宝典-常见整理(重复率高)
  13. 智能型炉温测试仪kic x5软件,KIC X5 炉温测试仪产品说明ppt课件
  14. RAID 容量计算器
  15. b站python直播批量发送弹幕_Python实现自动发送B站直播弹幕软件
  16. 找谷歌地图上任意点的经纬度
  17. 传输层 TCP 拥塞控制(3):快速重传与快速恢复
  18. 4.贪心算法 含例题
  19. 前端实习生应该掌握什么技能?
  20. [人力资源机器]19关倒计时-攻略

热门文章

  1. Linux内核编译及系统裁剪
  2. Neo4j通过excel导入实体及关系时总是显示no changes,no records
  3. 电影制作的“文艺复兴”-你准备好了吗?
  4. HTC VIVE 基础开发1
  5. 实用的程序员面试技巧
  6. 真实项目之【邀请码活动模块】实现思路
  7. 《大象 Thinking in UML》学习笔记(十)——需求分析
  8. vscode Nuget Package Manager 提示 Versioning information could not be retrieved from the NuGet package
  9. 从开发人员走向架构师三步曲
  10. 基于Vshare插件实现vue分享功能