博客
关于我
(五)UGUI源码分析之Rebuild(布局重建、图形重绘)
阅读量:508 次
发布时间:2019-03-07

本文共 2255 字,大约阅读时间需要 7 分钟。

CanvasUpdateRegistry 和 ICanvasElement 相关 Rebuild 操作 时机

最近在优化 UI 组件性能时,深入研究了 CanvasUpdateRegistry、ICanvasElement、LayoutGroup 等相关组件的工作原理,尤其是 Rebuild 操作的实现细节。通过阅读源码和调试实例,整理出以下关键信息,供开发者参考。


一、添加 需要 Rebuild 的 元素 时机

1. 自身 继承 ICanvasElement 的 类

ICanvasElement 接口的继承类(如 ScrollRect、Toggle、Slider 等)在以下时机添加布局元素:

  • ScrollRect

    • OnEnable 方法
    • SetDirtyCaching 方法(触发时赋值 viewport、horizontalScrollbar、verticalScrollbar 等属性时)
    • OnDisable 方法,会移除元素,并调用 LayoutRebuilder.MarkLayoutForRebuild(rectTransform)
    • OnRectTransformDimensionsChange(RectTransform尺寸变化时)
    • horizontalScrollbarVisibility、verticalScrollbarVisibility 修改时
  • Toggle

    • 编辑模式下,在PrefabUtility.IsPartOfPrefabAsset(this) 为 false 且未运行游戏时,调用 OnValidate 方法进行添加布局元素。
  • Slider

    • 同样在编辑模式下,调用 OnValidate 方法进行添加布局元素。

2. 非继承 ICanvasElement 的 类

对于不直接继承 ICanvasElement 的组件,需要通过 LayoutRebuilder.MarkLayoutForRebuild(rectTransform) 方法将父物体中拥有 LayoutGroup 组件的物体封装到布局列表中。具体规则如下:

  • 如果当前物体有 LayoutGroup 且父物体无,则将当前物体添加到布局列表。
  • 如果父物体有 LayoutGroup 而当前物体无,则将父物体添加到布局列表。
  • 如果当前物体和父物体均无 LayoutGroup,则不添加。

二、各大类的 Rebuild 方法 具体 内容

1. 只参与布局(布局前、布局后)

  • ScrollRect

    • 具体操作通过自身的 Rebuild 方法(继承自 ICanvasElement)。
    • 在编辑模式下,Toggle 和 Slider 会调用 onValueChange 方法(布局前)。
    • 借助 LayoutRebuilder 进行计算,确定水平和垂直布局容器的合适尺寸,然后确定子物体的尺寸和位置。
  • LayoutRebuilder

    • 在布局过程中,通过 Rebuild 方法计算 Horizontal 和 Vertical 布局容器的正确大小,并更新子物体的尺寸和位置。
  • 其他布局相关类(如 HorizontalLayout、VerticalLayout、GridLayout):

    • 在 Rebuild 方法中,根据容器大小参数计算子物体布局信息,完成布局更新。

2. 只参与绘制(绘制前、绘制后)

  • Graphic 类及其子类(如 Text、Image 等):

    • 在绘制前,通过 SetVerticesDirty(V)、SetMaterialDirty(M)、OnCullingChanged(C)等方法标记为需要更新。
    • 其他触发绘制列表更新的时机包括:
      • Text 类:设置 text、supportRichText、resizeTextForBestFit 等属性时。
      • Image 类:设置 type、preserveAspect、fillCenter 等属性时,或在 OnCanvasHierarchyChanged 方法。
      • Shadow/Outline:设置 useGraphicAlpha、effectDistance、effectColor 等属性时。
  • RawImage、BaseMeshEffect、AspectRatioFitter 等

    • 在属性改变时调用 V 方法(如 texture 改变、uvRect 改变)。
    • 或在 RectTransform 属性变化时触发(如 OnRectTransformDimensionsChange)。

三、其他注意事项

  • _prefabInstanceUpdated 事件:
    • 在 PrefabUtility namespace注册了 OnPrefabInstanceUpdates 方法。
    • 当预制体实例化后,会调用 LayoutRebuilder.MarkLayoutForRebuild(rectTransform)。
    • 主要用于更新场景中的 LayoutGroup 组件。

四、总结

通过以上分析,可以清晰地知道哪些组件在何时触发 LayoutRebuild 和 GraphicRebuild 操作。理解 Rebuild 的触发时机,对于优化 UI 更新效率至关重要。建议在实际开发中,结合项目需求,对相关组件的 Rebuild 行为做细致调试和优化。

如有疑问或需要更深入的实现细节,可以参考 UnityEditor.UI namespace 中的相关类实现。

转载地址:http://teucz.baihongyu.com/

你可能感兴趣的文章
object detection错误之Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERROR
查看>>
Object of type 'ndarray' is not JSON serializable
查看>>
Object Oriented Programming in JavaScript
查看>>
OBJECTIVE C (XCODE) 绘图功能简介(转载)
查看>>
Objective-C——判断对象等同性
查看>>
Objective-C之成魔之路【7-类、对象和方法】
查看>>
Objective-C享元模式(Flyweight)
查看>>
Objective-C以递归的方式实现二叉搜索树算法(附完整源码)
查看>>
Objective-C内存管理教程和原理剖析(三)
查看>>
Objective-C实现 Greedy Best First Search最佳优先搜索算法(附完整源码)
查看>>
Objective-C实现 jugglerSequence杂耍者序列算法 (附完整源码)
查看>>
Objective-C实现1000 位斐波那契数算法(附完整源码)
查看>>
Objective-C实现2 个数字之间的算术几何平均值算法(附完整源码)
查看>>
Objective-C实现2d 表面渲染 3d 点算法(附完整源码)
查看>>
Objective-C实现2D变换算法(附完整源码)
查看>>
Objective-C实现3n+1猜想(附完整源码)
查看>>
Objective-C实现3n+1猜想(附完整源码)
查看>>
Objective-C实现9x9乘法表算法(附完整源码)
查看>>
Objective-C实现9×9二维数组数独算法(附完整源码)
查看>>
Objective-C实现A-Star算法(附完整源码)
查看>>