using UnityEngine; using UnityEngine.UI; namespace Cryville.Common.Unity.UI { [AddComponentMenu("Layout/Single Layout Group")] [ExecuteAlways] public class SingleLayoutGroup : LayoutGroup { [SerializeField] protected bool m_ChildForceExpandWidth = true; [SerializeField] protected bool m_ChildForceExpandHeight = true; [SerializeField] protected bool m_ChildControlWidth = true; [SerializeField] protected bool m_ChildControlHeight = true; [SerializeField] protected bool m_ChildScaleWidth; [SerializeField] protected bool m_ChildScaleHeight; public override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); CalcAlongAxis(0); } public override void CalculateLayoutInputVertical() { CalcAlongAxis(1); } public override void SetLayoutHorizontal() { SetChildrenAlongAxis(0); } public override void SetLayoutVertical() { SetChildrenAlongAxis(1); } protected void CalcAlongAxis(int axis) { float combinedPadding = (axis == 0) ? padding.horizontal : padding.vertical; bool controlSize = (axis == 0) ? m_ChildControlWidth : m_ChildControlHeight; bool useScale = (axis == 0) ? m_ChildScaleWidth : m_ChildScaleHeight; bool childForceExpandSize = (axis == 0) ? m_ChildForceExpandWidth : m_ChildForceExpandHeight; float totalMin = combinedPadding; float totalPreferred = combinedPadding; float totalFlexible = 0f; RectTransform child = rectChildren[0]; GetChildSizes(child, axis, controlSize, childForceExpandSize, out var min, out var preferred, out var flexible); if (useScale) { float scaleFactor = child.localScale[axis]; min *= scaleFactor; preferred *= scaleFactor; flexible *= scaleFactor; } totalMin = Mathf.Max(min + combinedPadding, totalMin); totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred); totalFlexible = Mathf.Max(flexible, totalFlexible); totalPreferred = Mathf.Max(totalMin, totalPreferred); SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis); } protected void SetChildrenAlongAxis(int axis) { float size = rectTransform.rect.size[axis]; bool controlSize = (axis == 0) ? m_ChildControlWidth : m_ChildControlHeight; bool useScale = (axis == 0) ? m_ChildScaleWidth : m_ChildScaleHeight; bool childForceExpandSize = (axis == 0) ? m_ChildForceExpandWidth : m_ChildForceExpandHeight; float alignmentOnAxis = GetAlignmentOnAxis(axis); float innerSize = size - ((axis == 0) ? padding.horizontal : padding.vertical); RectTransform child = rectChildren[0]; GetChildSizes(child, axis, controlSize, childForceExpandSize, out var min2, out var preferred2, out var flexible2); float scaleFactor2 = useScale ? child.localScale[axis] : 1f; float requiredSpace = Mathf.Clamp(innerSize, min2, (flexible2 > 0f) ? size : preferred2); float startOffset = GetStartOffset(axis, requiredSpace * scaleFactor2); if (controlSize) { SetChildAlongAxisWithScale(child, axis, startOffset, requiredSpace, scaleFactor2); } else { float offsetInCell2 = (requiredSpace - child.sizeDelta[axis]) * alignmentOnAxis; SetChildAlongAxisWithScale(child, axis, startOffset + offsetInCell2, scaleFactor2); } } void GetChildSizes(RectTransform child, int axis, bool controlSize, bool childForceExpand, out float min, out float preferred, out float flexible) { if (!controlSize) { min = child.sizeDelta[axis]; preferred = min; flexible = 0f; } else { min = LayoutUtility.GetMinSize(child, axis); preferred = LayoutUtility.GetPreferredSize(child, axis); flexible = LayoutUtility.GetFlexibleSize(child, axis); } if (childForceExpand) { flexible = Mathf.Max(flexible, 1f); } } } }