关于源码
关于源码可以参考这篇博客下载或调试。
CanvasUpdateRegistry
单例
UGUI与Canvas之间的中介
继承
ICanvasElement
接口的组件都可以注册到它,它监听了Canvas即将渲染的事件
,并调用已注册组件的Rebuild
等方法CanvasUpdateRegistry的构造函数:
protected CanvasUpdateRegistry() { Canvas.willRenderCanvases += PerformUpdate; }
willRenderCanvases是静态类Canvas的静态事件,事件是一种特殊的委托。在CanvasUpdateRegistry的构造函数里,为willRenderCanvases事件添加了一个监听PerformUpdate。从字面意思我们可以知道,在渲染(所有)Canvas之前会抛出willRenderCanvases事件,继而调用到CanvasUpdateRegistry的PerformUpdate方法。
ICanvasElement:
public interface ICanvasElement { void Rebuild(CanvasUpdate executing); Transform transform { get; } void LayoutComplete(); void GraphicUpdateComplete(); // due to unity overriding null check // we need this as something may not be null // but may be destroyed bool IsDestroyed(); }
UGUI组件都继承自
UIBehaviour
,而UIBehavior实现了IsDestroyed
方法。所有组件都继承自Component
,而Component
实现了transform
属性。所以继承自ICanvasElement
的UGUI组件不必再实现这两个成员。另外三个Rebuild
(重建)、LayoutComplete
(布局完成)、GraphicUpdateComplete
(图像更新完成)就需要在代码中实现。(一个例外LayoutRebuilder
,它并不是组件,是一个负责重建布局的类)CanvasUpdateRegistry维护了两个索引集,布局重建序列(m_LayoutRebuildQueue),一个是图像重建序列(m_GraphicRebuildQueue):
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
移除注册元素。CanvasUpdate:除了最后一个枚举项,其他五个项分别代表了布局的三个阶段和渲染的两个阶段。
public enum CanvasUpdate { Prelayout = 0, Layout = 1, PostLayout = 2, PreRender = 3, LatePreRender = 4, MaxUpdateValue = 5 }
PerformUpdate
里会从两个序列里删除掉不可用的元素(如果元素是LayoutRebuilder,会调用的LayoutComplete)。接着对m_LayoutRebuildQueue
依据父对象数量进行排序。然后分别以Prelayout
、Layout
和PostLayout
为参数调用每一个元素的Rebuild
方法,然后调用所有元素的LayoutComplete
方法并清除所有元素。完成布局之后,调用ClipperRegistry.instance.Cull()
。(ClipperRegistry
是另外一个注册处单例,用于在布局之后调用组件的修剪方法。)继而分别以PreRender
和LatePreRender
为参数调用m_GraphicRebuildQueue
的每一个元素的Rebuild
方法,然后调用所有元素的LayoutComplete
方法并清除所有元素。至此,一个完整的更新流程就完成了。