Runtime类图分析

CanvasUpdateRegistry

管理着两个队列:

private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>();private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>();

m_LayoutRebuildQueue是通过RegisterCanvasElementForLayoutRebuild

TryRegisterCanvasElementForLayoutRebuild方法添加元素。

m_GraphicRebuildQueue是通过RegisterCanvasElementForGraphicRebuild

TryRegisterCanvasElementForGraphicRebuild方法添加元素。

二者通过UnRegisterCanvasElementForRebuild移除注册元素。

在构造函数中向Canvas的willRenderCanvases 事件注册了更新函数(PerformUpdate),以用来响应重建。

Canvas.willRenderCanvases += PerformUpdate;

Canvas在渲染前会调用willRenderCanvases,即执行PerformUpdate ,方法如下:

        private void PerformUpdate(){UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout);CleanInvalidItems();m_PerformingLayoutUpdate = true;m_LayoutRebuildQueue.Sort(s_SortLayoutFunction);for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++){for (int j = 0; j < m_LayoutRebuildQueue.Count; j++){var rebuild = instance.m_LayoutRebuildQueue[j];try{if (ObjectValidForUpdate(rebuild))rebuild.Rebuild((CanvasUpdate)i);}catch (Exception e){Debug.LogException(e, rebuild.transform);}}}for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i)m_LayoutRebuildQueue[i].LayoutComplete();instance.m_LayoutRebuildQueue.Clear();m_PerformingLayoutUpdate = false;// now layout is complete do culling...ClipperRegistry.instance.Cull();m_PerformingGraphicUpdate = true;for (var i = (int)CanvasUpdate.PreRender; i < (int)CanvasUpdate.MaxUpdateValue; i++){for (var k = 0; k < instance.m_GraphicRebuildQueue.Count; k++){try{var element = instance.m_GraphicRebuildQueue[k];if (ObjectValidForUpdate(element))element.Rebuild((CanvasUpdate)i);}catch (Exception e){Debug.LogException(e, instance.m_GraphicRebuildQueue[k].transform);}}}for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i)m_GraphicRebuildQueue[i].GraphicUpdateComplete();instance.m_GraphicRebuildQueue.Clear();m_PerformingGraphicUpdate = false;UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout);}

流程如下:

首先调用 CleanInvalidItems删除不可用(为null或者IsDestroyed)的元素。

布局更新开始设置标识位m_PerformingLayoutUpdate为true。

对m_LayoutRebuildQueue依据父对象的数量进行排序:m_LayoutRebuildQueue.Sort(s_SortLayoutFunction)。

分别以PreLayout,Layout,PostLayout的参数顺序调用每一个元素的Rebuild方法。

其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。

调用所有元素的LayoutComplete方法。
清除布局重建序列中的所有元素m_LayoutRebuildQueue.Clear()。
布局更新结束设置标志位m_PerformingLayoutUpdate = false。

完成布局后,调用组件的修剪方法ClipperRegistry.instance.Cull()。

图形更新开始设置标识位m_PerformingGraphicUpdate为true。

以PreRender,LatePreRender,MaxUpdateValue的参数顺序调用每一个元素的Rebulid方法。

其中在Rebuild之前需要判断这个元素是否有效(不为空且为Unity的Object类型)。

调用所有元素的GraphicUpdateComplete方法。
清除图形重建序列中的所有元素m_GraphicRebuildQueue.Clear()。
图形更新结束设置标志位m_PerformingGraphicUpdate = false。

CanvasUpdate

定义重建时的优先级顺序:

    public enum CanvasUpdate{/// <summary>/// Called before layout./// </summary>Prelayout = 0,/// <summary>/// Called for layout./// </summary>Layout = 1,/// <summary>/// Called after layout./// </summary>PostLayout = 2,/// <summary>/// Called before rendering./// </summary>PreRender = 3,/// <summary>/// Called late, before render./// </summary>LatePreRender = 4,/// <summary>/// Max enum value. Always last./// </summary>MaxUpdateValue = 5}

ICanvasElement

需要在Canvas绘制更新调用前重建的元素接口。

    /// <summary>/// This is an element that can live on a Canvas./// </summary>public interface ICanvasElement{/// <summary>/// Rebuild the element for the given stage./// </summary>/// <param name="executing">The current CanvasUpdate stage being rebuild.</param>void Rebuild(CanvasUpdate executing);/// <summary>/// Get the transform associated with the ICanvasElement./// </summary>Transform transform { get; }/// <summary>/// Callback sent when this ICanvasElement has completed layout./// </summary>void LayoutComplete();/// <summary>/// Callback sent when this ICanvasElement has completed Graphic rebuild./// </summary>void GraphicUpdateComplete();/// <summary>/// Used if the native representation has been destroyed./// </summary>/// <returns>Return true if the element is considered destroyed.</returns>bool IsDestroyed();}

Rebuild实际的重建方法。

LayoutComplete在布局重建完成后回调。

GraphicUpdateComplete在图形重建完成后回调。

IsDestroyed判断当前元素是否已经不需要参与重建了。

ClipperRegistry

内部维护着一个IClipper接口的列表

 readonly IndexedSet<IClipper> m_Clippers = new IndexedSet<IClipper>();

提供Register方法加入一个IClipper到此列表中,

Unregister移除m_Clippers 列表中的指定IClipper,

在Cull方法中遍历此列表,分别调用它们的PerformClipping方法。

脏标记

标记延迟执行,优化重新渲染的手段。

详情请见:游戏设计模式:https://gpp.tkchu.me/dirty-flag.html

例如在Graphic 中存在三种脏标分别代表三种等待重建。

尺寸改变时(RectTransformDimensions):LayoutRebuild 布局重建;
尺寸、颜色改变时:Vertices to GraphicRebuild 图像重建;
材质改变时:Material to GraphicRebuild 图像重建。

层级改变(OnTransformParentChanged)、应用动画属性(OnDidApplyAnimationProperties) :All to Rebuild 重建所有,包括布局重建和图像重建。

UGUI源码剖析(CanvasUpdateSystem 画布刷新系统)相关推荐

  1. [UGUI源码剖析]—Rebuild 网格重建(画布刷新)系统

    几个比较重要的类和接口: Canvas.CanvasUpdateRegistry.ClipperRegistry.LayoutRebuilder.LayoutGroup.Graphics.Maskab ...

  2. CanvasUpdateSystem 画布刷新系统

    制作UI过程,添加Canvas组件将会打断和之前元素DrawCall的合并,每个Canvas都会开始一个全新的DrawCall,当Canvas需要重绘的时候会调用SendWillRenderCanva ...

  3. UGUI源码解析(LayoutSystem布局系统)

    Runtime类图 ILayoutElement 布局元素接口,是布局的接收方.如果某个类实现了这个接口,那么就会在应用布局时自动完成对它的位置信息及大小的布局计算. ILayoutControlle ...

  4. UGUI源码剖析(Image)

    Runtime类图分析 Image继承了MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastF ...

  5. UGUI源码分析:GridLayoutGroup网格布局组件与ContentSizeFitter尺寸调节组件

    系列 UGUI源码分析系列总览 相关前置: UGUI CanvasUpdateSystem源码分析 UGUI源码分析:LayoutSystem布局系统 UGUI源码分析:LayoutGroup中的纵横 ...

  6. UGUI源码分析:LayoutGroup中的纵横布局组件(HorizontalOrVerticalLayoutGroup)

    系列 UGUI源码分析系列总览 相关前置: UGUI CanvasUpdateSystem源码分析 UGUI源码分析:LayoutSystem布局系统 文章目录 系列 UML图一览 LayoutGro ...

  7. Python猫荐书系统之四:《Python源码剖析》

    大家好,新一期的荐书栏目如期跟大家见面了. 先来看看今天的主角是谁:<Python源码剖析--深度探索动态语言核心技术>,2008年出版,作者 @陈儒 ,评分8.7分. 是的,你没看错,出 ...

  8. ugui源码_UGUI 源码笔记(一)文件结构和部分组件使用

    这是我阅读 UGUI 源码记录的相关笔记,共三部分.文件结构和部分组件使用.输入事件.核心部分 ZeroyiQ:UGUI 源码笔记(一)文件结构和部分组件使用 ZeroyiQ:UGUI 源码笔记(二) ...

  9. Chrome源码剖析、上--多线程模型、进程通信、进程模型

    Chrome源码剖析.上 原著:duguguiyu. 整理:July. 时间:二零一一年四月二日. 出处:http://blog.csdn.net/v_JULY_v. 说明:此Chrome源码剖析很大 ...

  10. Chrome源码剖析 上--多线程模型 进程通信 进程模型

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! Chro ...

最新文章

  1. android开发获取应用本身耗电量_别找了,Android常用自动化工具全在这儿了!
  2. 导致用户体验差造成网站跳出率过高的原因有哪些?
  3. struts2.0和struts1.x的区别
  4. CSDN移动博文集锦之Android核心分析 (Z)
  5. Android之用命令uninstall卸载apk和用 -i 过滤日志忽略大小写
  6. 【51单片机快速入门指南】9:省电模式(低功耗)
  7. host ntrip 千寻rtk_最新测量干货:南方银河1和银河1Plus RTK设备连接千寻cors账号的设置方法...
  8. mybatis $和#源代码分析
  9. 数字音频特效的软件实现项目
  10. 设计海报|字符海报怎么玩?
  11. 北大AI第八讲 李航 自然语言处理的现实与挑战
  12. 张量(tensor)的理解
  13. 支持IE8的文件上传
  14. python3 下 tkinter 的网页监控小程序
  15. Android 动画丢帧问题
  16. Windows Mobile 6.x 下改Tahoma字体+微软雅黑说明
  17. USB接口、手机接口
  18. 下载kaggle比赛的数据集
  19. 淘宝网店商品哪个时间段是最佳上架时间?
  20. Kubernetes Scheduler源码分析--启动过程与多队列缓存(续)

热门文章

  1. 盛语小智教育机器人是骗人的_盛语小智机器人骗局揭露【是不是真的有效】多久可以见...
  2. cv::Mat转换为QImage错误
  3. sphinx linux,sphinx使用及其简单配置方法
  4. 关于用EAC抓轨的测试 (转载)
  5. vue从零搭建一个前中后台权限管理模板
  6. 百钱买百鸡问题的解法与思路
  7. WORD2003无法打开WORD2000文档解决方法
  8. RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you
  9. 自己动手写ORB特征
  10. 网络狂飙(netspeeder) v3.28 游戏版 怎么用