Layout为ugui自动排版实现;
ugui驱动layout刷新组件 CanvasUpdateRegistry:
protected CanvasUpdateRegistry()
{
//驱动ui build
Canvas.willRenderCanvases += PerformUpdate;
}
private void PerformUpdate()
{
UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout);
CleanInvalidItems();
m_PerformingLayoutUpdate = true;
//节点从浅到深排序,Layout会控制子节点的位置,得先确定父节点的位置
m_LayoutRebuildQueue.Sort(s_SortLayoutFunction);
for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++)
{
UnityEngine.Profiling.Profiler.BeginSample(m_CanvasUpdateProfilerStrings[i]);
for (int j = 0; j < m_LayoutRebuildQueue.Count; j++)
{
var rebuild = m_LayoutRebuildQueue[j];
try
{
if (ObjectValidForUpdate(rebuild))
rebuild.Rebuild((CanvasUpdate)i); //驱动layout刷新
}
catch (Exception e)
{
Debug.LogException(e, rebuild.transform);
}
}
UnityEngine.Profiling.Profiler.EndSample();
}
for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i)
m_LayoutRebuildQueue[i].LayoutComplete();
m_LayoutRebuildQueue.Clear();
m_PerformingLayoutUpdate = false;
UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout);
}
添加layout builder的组件LayoutRebuilder:
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine.Pool;
namespace UnityEngine.UI
{
/// <summary>
/// Wrapper class for managing layout rebuilding of CanvasElement.
/// </summary>
public class LayoutRebuilder : ICanvasElement
{
private RectTransform m_ToRebuild;
//There are a few of reasons we need to cache the Hash fromt he transform:
// - This is a ValueType (struct) and .Net calculates Hash from the Value Type fields.
// - The key of a Dictionary should have a constant Hash value.
// - It's possible for the Transform to get nulled from the Native side.
// We use this struct with the IndexedSet container, which uses a dictionary as part of it's implementation
// So this struct gets used as a key to a dictionary, so we need to guarantee a constant Hash value.
//LayoutRebuilder会用作dictionary的key,用确定的Hash值保证同一个RectTransform对应一个LayoutRebuilder
private int m_CachedHashFromTransform;
//对象池
static ObjectPool<LayoutRebuilder> s_Rebuilders = new ObjectPool<LayoutRebuilder>(() => new LayoutRebuilder(), null, x => x.Clear());
private void Initialize(RectTransform controller)
{
m_ToRebuild = controller;
m_CachedHashFromTransform = controller.GetHashCode();
}
private void Clear()
{
m_ToRebuild = null;
m_CachedHashFromTransform = 0;
}
static LayoutRebuilder()
{
RectTransform.reapplyDrivenProperties += ReapplyDrivenProperties;
}
static void ReapplyDrivenProperties(RectTransform driven)
{
MarkLayoutForRebuild(driven);
}
public Transform transform { get { return m_ToRebuild; }}
/// <summary>
/// Has the native representation of this LayoutRebuilder been destroyed?
/// </summary>
public bool IsDestroyed()
{
return m_ToRebuild == null;
}
static void StripDisabledBehavioursFromList(List<Component> components)
{
components.RemoveAll(e => e is Behaviour && !((Behaviour)e).isActiveAndEnabled);
}
/// <summary>
/// Forces an immediate rebuild of the layout element and child layout elements affected by the calculations.
/// </summary>
/// <param name="layoutRoot">The layout element to perform the layout rebuild on.</param>