summaryrefslogtreecommitdiff
path: root/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-05-08 23:15:13 +0800
committerchai <chaifix@163.com>2021-05-08 23:15:13 +0800
commitd07e14add74e017b52ab2371efeea1aa4ea10ced (patch)
treeefd07869326e4c428f5bfe43fad0c2583d32a401 /Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs
+init
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs')
-rw-r--r--Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs233
1 files changed, 233 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs
new file mode 100644
index 0000000..5fba1cc
--- /dev/null
+++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Layout/LayoutRebuilder.cs
@@ -0,0 +1,233 @@
+using System.Collections.Generic;
+using UnityEngine.Events;
+
+namespace UnityEngine.UI
+{
+ public class LayoutRebuilder : ICanvasElement
+ {
+ // m_ToRebuild是一个ILayoutGroup
+ private RectTransform m_ToRebuild;
+ //There are a few of reasons we need to cache the Hash from the 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.
+ private int m_CachedHashFromTransform;
+
+ // 一个rebuilder结构的池子
+ static ObjectPool<LayoutRebuilder> s_Rebuilders = new ObjectPool<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; }}
+
+ public bool IsDestroyed()
+ {
+ return m_ToRebuild == null;
+ }
+
+ static void StripDisabledBehavioursFromList(List<Component> components)
+ {
+ components.RemoveAll(e => e is Behaviour && !((Behaviour)e).isActiveAndEnabled);
+ }
+
+ // 立即重新布局一次,而不用等到帧末尾CanvasUpdateReigstry.PerformUpdate的时候
+ public static void ForceRebuildLayoutImmediate(RectTransform layoutRoot)
+ {
+ var rebuilder = s_Rebuilders.Get();
+ rebuilder.Initialize(layoutRoot);
+ rebuilder.Rebuild(CanvasUpdate.Layout);
+ s_Rebuilders.Release(rebuilder);
+ }
+
+ public void Rebuild(CanvasUpdate executing)
+ {
+ switch (executing)
+ {
+ case CanvasUpdate.Layout:
+ // It's unfortunate that we'll perform the same GetComponents querys for the tree 2 times,
+ // but each tree have to be fully iterated before going to the next action,
+ // so reusing the results would entail storing results in a Dictionary or similar,
+ // which is probably a bigger overhead than performing GetComponents multiple times.
+ PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputHorizontal());
+ PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutHorizontal());
+ PerformLayoutCalculation(m_ToRebuild, e => (e as ILayoutElement).CalculateLayoutInputVertical());
+ PerformLayoutControl(m_ToRebuild, e => (e as ILayoutController).SetLayoutVertical());
+ break;
+ }
+ }
+
+ // 从上到下遍历,执行action
+ private void PerformLayoutControl(RectTransform rect, UnityAction<Component> action)
+ {
+ if (rect == null)
+ return;
+
+ var components = ListPool<Component>.Get();
+ rect.GetComponents(typeof(ILayoutController), components);
+ StripDisabledBehavioursFromList(components);
+
+ // If there are no controllers on this rect we can skip this entire sub-tree
+ // We don't need to consider controllers on children deeper in the sub-tree either,
+ // since they will be their own roots.
+ if (components.Count > 0)
+ {
+ //
+ // Layout control needs to executed top down with parents being done before their children,
+ // because the children rely on the sizes of the parents.
+
+ // 做两次遍历,先执行ILayoutSelfController比如ContentSizeFitter,再执行ILayoutGroup
+
+ // First call layout controllers that may change their own RectTransform
+ for (int i = 0; i < components.Count; i++)
+ if (components[i] is ILayoutSelfController)
+ action(components[i]);
+
+ // Then call the remaining, such as layout groups that change their children, taking their own RectTransform size into account.
+ for (int i = 0; i < components.Count; i++)
+ if (!(components[i] is ILayoutSelfController))
+ action(components[i]);
+
+ for (int i = 0; i < rect.childCount; i++)
+ PerformLayoutControl(rect.GetChild(i) as RectTransform, action);
+ }
+
+ ListPool<Component>.Release(components);
+ }
+
+ private void PerformLayoutCalculation(RectTransform rect, UnityAction<Component> action)
+ {
+ if (rect == null)
+ return;
+
+ var components = ListPool<Component>.Get();
+ rect.GetComponents(typeof(ILayoutElement), components);
+ StripDisabledBehavioursFromList(components);
+
+ // If there are no controllers on this rect we can skip this entire sub-tree
+ // We don't need to consider controllers on children deeper in the sub-tree either,
+ // since they will be their own roots.
+ if (components.Count > 0 || rect.GetComponent(typeof(ILayoutGroup)))
+ {
+
+ // 先从子节点开始,最后到父节点,这样父节点可以得到子节点的信息
+ // Layout calculations needs to executed bottom up with children being done before their parents,
+ // because the parent calculated sizes rely on the sizes of the children.
+
+ for (int i = 0; i < rect.childCount; i++)
+ PerformLayoutCalculation(rect.GetChild(i) as RectTransform, action);
+
+ for (int i = 0; i < components.Count; i++)
+ action(components[i]);
+ }
+
+ ListPool<Component>.Release(components);
+ }
+
+ // 找到rect祖先节点中的layoutGroup并加入队列
+ public static void MarkLayoutForRebuild(RectTransform rect)
+ {
+ if (rect == null)
+ return;
+
+ var comps = ListPool<Component>.Get();
+ RectTransform layoutRoot = rect; // 祖先节点中的layoutGroup
+ while (true)
+ {
+ var parent = layoutRoot.parent as RectTransform;
+ if (!ValidLayoutGroup(parent, comps))
+ break;
+ layoutRoot = parent;
+ }
+
+ // We know the layout root is valid if it's not the same as the rect,
+ // since we checked that above. But if they're the same we still need to check.
+ if (layoutRoot == rect && !ValidController(layoutRoot, comps))
+ {
+ ListPool<Component>.Release(comps);
+ return;
+ }
+
+ MarkLayoutRootForRebuild(layoutRoot);
+ ListPool<Component>.Release(comps);
+ }
+
+ private static bool ValidLayoutGroup(RectTransform parent, List<Component> comps)
+ {
+ if (parent == null)
+ return false;
+
+ parent.GetComponents(typeof(ILayoutGroup), comps);
+ StripDisabledBehavioursFromList(comps);
+ var validCount = comps.Count > 0;
+ return validCount;
+ }
+
+ private static bool ValidController(RectTransform layoutRoot, List<Component> comps)
+ {
+ if (layoutRoot == null)
+ return false;
+ layoutRoot.GetComponents(typeof(ILayoutController), comps);
+ StripDisabledBehavioursFromList(comps);
+ var valid = comps.Count > 0;
+ return valid;
+ }
+
+ private static void MarkLayoutRootForRebuild(RectTransform controller)
+ {
+ if (controller == null)
+ return;
+
+ var rebuilder = s_Rebuilders.Get();
+ rebuilder.Initialize(controller);
+ // 注册到CanvasUpdateRegistry里
+ if (!CanvasUpdateRegistry.TryRegisterCanvasElementForLayoutRebuild(rebuilder))
+ s_Rebuilders.Release(rebuilder);
+ }
+
+ public void LayoutComplete()
+ {
+ // 放回池子里
+ s_Rebuilders.Release(this);
+ }
+
+ public void GraphicUpdateComplete()
+ {}
+
+ public override int GetHashCode()
+ {
+ return m_CachedHashFromTransform;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj.GetHashCode() == GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return "(Layout Rebuilder for) " + m_ToRebuild;
+ }
+ }
+}