【UGUI】自動佈局
阿新 • • 發佈:2018-11-20
UGUI自動佈局一直適應 GridLayoutGroup,但是,使用grid時有一個很嚴重的問題就是:當開啟Profiler中的Deep Profile時,整個Unity都會崩潰.(目前使用版本v5.6.0)此外,還有一個問題,但是我給忘了...
所以,還是自己動手造輪子吧,程式碼如下:
using UnityEngine; /// <summary> /// Introduction: UILayout, UI自動佈局,替代GridLayoutGroup, 子節點改變時需要自行呼叫 Rebuild /// Author: Garson /// Time: /// </summary> [RequireComponent(typeof(RectTransform))] public class UILayout : MonoBehaviour { [SerializeField]//邊距 private RectOffset m_Padding = new RectOffset(); public RectOffset padding { get { return m_Padding; } set { SetProperty(ref m_Padding, value); } } [SerializeField]//單元格大小 private Vector2 m_CellSize = new Vector2(100, 100); public Vector2 cellSize { get { return m_CellSize; } set { SetProperty(ref m_CellSize, value);} } [SerializeField]//開始排布位置 private StartCorner m_StartCorner; public StartCorner startCorner { get { return m_StartCorner; } set { SetProperty(ref m_StartCorner, value);} } [SerializeField]//排列方式 private Arrangement m_Arrangement; public Arrangement arrangement { get { return m_Arrangement; } set { SetProperty(ref m_Arrangement, value);} } [Tooltip("<=0自動計算")] [SerializeField]//每行數目,<=0自動計算 private int m_FixedCount; public int fixedCount { get { return m_FixedCount; } set { SetProperty(ref m_FixedCount, value); } } [SerializeField] private Vector2 m_Space;//行列間距 public Vector2 space { get { return m_Space; } set { SetProperty(ref m_Space, value); } } private Vector2 m_WrapSize;//排布後該元件應該大小 public Vector2 wrapSize { get { return m_WrapSize; } } private RectTransform m_rectTransform; private RectTransform rectTransform { get { if(m_rectTransform==null)m_rectTransform=transform as RectTransform;return m_rectTransform;} } public void Rebuild() { RectTransform.Edge edgeX = RectTransform.Edge.Left, edgeY= RectTransform.Edge.Top; float paddingX = 0, paddingY = 0, sizeX = 0, sizeY = 0; switch (m_StartCorner) { case StartCorner.TopLeft: edgeY = RectTransform.Edge.Top; edgeX = RectTransform.Edge.Left; paddingX = m_Padding.left; paddingY = m_Padding.top; sizeX = m_Padding.right; sizeY = m_Padding.bottom; break; case StartCorner.TopRight: edgeY = RectTransform.Edge.Top; edgeX = RectTransform.Edge.Right; paddingX = m_Padding.right; paddingY = m_Padding.top; sizeX = m_Padding.left; sizeY = m_Padding.bottom; break; case StartCorner.BottomLeft: edgeY = RectTransform.Edge.Bottom; edgeX = RectTransform.Edge.Left; paddingX = m_Padding.left; paddingY = m_Padding.bottom; sizeX = m_Padding.right; sizeY = m_Padding.top; break; case StartCorner.BottomRight: edgeY = RectTransform.Edge.Bottom; edgeX = RectTransform.Edge.Right; paddingX = m_Padding.right; paddingY = m_Padding.bottom; sizeX = m_Padding.left; sizeY = m_Padding.top; break; } int axis = 0; int preferCount = m_FixedCount; float tem = 0; m_WrapSize = Vector2.zero; switch (m_Arrangement) { case Arrangement.HorizontalFlow: axis = 0; tem = paddingX; if (m_FixedCount <= 0) { preferCount = Mathf.FloorToInt(rectTransform.rect.size.x / m_CellSize.x); preferCount = preferCount > 0 ? preferCount : 1; } break; case Arrangement.VerticalFlow: axis = 1; tem = paddingY; if (m_FixedCount <= 0) { preferCount = Mathf.FloorToInt(rectTransform.rect.size.y / m_CellSize.y); preferCount = preferCount > 0 ? preferCount : 1; } break; case Arrangement.Horizontal: axis = 0; preferCount = int.MaxValue; tem = paddingX; break; case Arrangement.Vertical: axis = 1; preferCount = int.MaxValue; tem = paddingY; break; } int flag = 0; for (int i = 0; i < transform.childCount; i++) { if (flag >= preferCount) { if (axis == 0) { tem = paddingX; paddingY += m_Space.y + m_CellSize.y; } else { tem = paddingY; paddingX += m_Space.x + m_CellSize.x; } flag = 0; } var child = transform.GetChild(i) as RectTransform; if (child != null && child.gameObject.activeSelf) { if (axis == 0) { child.SetInsetAndSizeFromParentEdge(edgeX, tem, m_CellSize.x); child.SetInsetAndSizeFromParentEdge(edgeY, paddingY, m_CellSize.y); tem += m_Space.x + m_CellSize.x; if (tem - m_Space.x > m_WrapSize.x) m_WrapSize.x = tem - m_Space.x; m_WrapSize.y = paddingY + m_CellSize.y; } else { child.SetInsetAndSizeFromParentEdge(edgeX, paddingX, m_CellSize.x); child.SetInsetAndSizeFromParentEdge(edgeY, tem, m_CellSize.y); tem += m_Space.y + m_CellSize.y; if (tem - m_Space.y > m_WrapSize.y) m_WrapSize.y = tem - m_Space.y; m_WrapSize.x = paddingX + m_CellSize.x; } flag++; } } m_WrapSize.x += sizeX; m_WrapSize.y += sizeY; } public void SetPadding(int left, int right, int top, int bottom) { padding = new RectOffset(left, right, top, bottom); } public void SetStartCorner(int start) { startCorner = (StartCorner) start; } public void SetArrangement(int arrange) { arrangement = (Arrangement) arrange; } private void SetProperty<T>(ref T currentValue, T newValue) { if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue))) return; currentValue = newValue; Rebuild(); } [LuaInterface.NoToLua] public enum StartCorner { TopLeft = 0, TopRight = 1, BottomLeft = 2, BottomRight = 3 } [LuaInterface.NoToLua] public enum Arrangement { //橫向流動,第一排、第二排... HorizontalFlow = 0, //縱向流動,第一列、第二列... VerticalFlow = 1, //橫排,相當於fixedCount=1效果 Horizontal = 2, //縱排,相當於fixedCount=1效果 Vertical = 3, } } #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(UILayout))] public class LayoutEditor : UnityEditor.Editor { public override void OnInspectorGUI() { base.OnInspectorGUI(); GUILayout.Space(10); if (GUILayout.Button("Rebuild")) { UILayout layout = target as UILayout; layout.Rebuild(); } } } #endif
其中 SetInsetAndSizeFromParentEdge 是呼叫的系統方法,作用是 設定元件相對於父節點的位置Edge距離(引數1)且在該軸上的長度(引數2)
注:任何子節點的改變都不會像gridlayoutgroup一樣重新整理,需要手動呼叫Rebuild,因為覺得沒有必要繼承UIBehaviour而是繼承了MonoBehaviour。 設定屬性會自動重新整理.
wrapSize 是rebuild後整個包裹區域應該的大小,可用於重新設定尺寸