protected virtual void GetChildSizes(IFastLayoutFeedback child, int axis, bool controlSize, bool childForceExpand, out float min, out float preferred, out float flexible) { if (!controlSize) { min = axis == 0 ? child.cachedRectWidth : child.cachedRectHeight; preferred = min; flexible = 0; } else { min = axis == 0 ? child.cachedMinWidth : child.cachedMinHeight; preferred = axis == 0 ? child.cachedPreferredWidth : child.cachedPreferredHeight; flexible = axis == 0 ? child.cachedFlexibleWidth : child.cachedFlexibleHeight; } //Prevent expand when child control size if (childForceExpand && (m_ForceExpandMode == ForceExpandMode.Inflate || !controlSize)) { flexible = Mathf.Max(flexible, 1); } //Prevent negative values on return flexible = Mathf.Max(flexible, 0); }
/// <summary> /// Calculate the layout element properties for this layout element along the given axis. /// </summary> /// <param name="axis">The axis to calculate for. 0 is horizontal and 1 is vertical.</param> /// <param name="isVertical">Is this group a vertical group?</param> protected virtual void CalcAlongAxis(int axis, bool isVertical) { 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 = 0; bool alongOtherAxis = (isVertical ^ (axis == 1)); for (int i = 0; i < children.Count; i++) { IFastLayoutFeedback child = children[i]; if (child == null) { return; } float min, preferred, flexible; GetChildSizes(children[i], axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); if (useScale) { float scaleFactor = child.rectTransform != null? child.rectTransform.localScale[axis] : 1.0f; min *= scaleFactor; preferred *= scaleFactor; flexible *= scaleFactor; } if (alongOtherAxis) { totalMin = Mathf.Max(min + combinedPadding, totalMin); totalPreferred = Mathf.Max(preferred + combinedPadding, totalPreferred); totalFlexible = Mathf.Max(flexible, totalFlexible); } else { totalMin += min + spacing; totalPreferred += preferred + spacing; // Increment flexible size with element's flexible size. totalFlexible += flexible; } } if (!alongOtherAxis && children.Count > 0) { totalMin -= spacing; totalPreferred -= spacing; } totalPreferred = Mathf.Max(totalMin, totalPreferred); SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, axis); }
public virtual void SetElementDirty(IFastLayoutFeedback driven, DrivenAxis dirtyAxis) { if (driven != null && (dirtyAxis.HasFlag(DrivenAxis.Ignore) || (dirtyAxis & childrenControlledAxis) != 0)) { if (!isDirty) { MarkLayoutForRebuild(); } _dirtyChildren.Add(driven); } }
public override void SetElementDirty(IFastLayoutFeedback driven, DrivenAxis dirtyAxis) { if (driven != null && (dirtyAxis.HasFlag(DrivenAxis.Ignore) || (dirtyAxis & childrenControlledAxis) != 0)) { if (!isDirty) { MarkLayoutForRebuild(); } //Special case when added element will affect other elements size if (dirtyAxis.HasFlag(DrivenAxis.Ignore) && ((isVertical && m_TotalFlexibleSize.y > 0) || (!isVertical && m_TotalFlexibleSize.x > 0))) { isAxisDirty = true; } _dirtyChildren.Add(driven); } }
protected virtual void GetChildAnchors(IFastLayoutFeedback child, int axis, bool controlSize, bool childForceExpand, Vector2 defaultAnchor, out Vector2 minAnchor, out Vector2 maxAnchor) { minAnchor = child != null && child.rectTransform != null? child.rectTransform.anchorMin : defaultAnchor; maxAnchor = child != null && child.rectTransform != null ? child.rectTransform.anchorMax : defaultAnchor; var drivenAxis = axis == 0 ? DrivenAxis.Horizontal : DrivenAxis.Vertical; var expand = !controlSize && (parentControlledAxis & drivenAxis) != 0; if (expand) { minAnchor[axis] = 0; maxAnchor[axis] = 1; } else { minAnchor[axis] = defaultAnchor[axis]; maxAnchor[axis] = minAnchor[axis]; } }
/// <summary> /// Set the positions and sizes of the child layout elements for the given axis. /// </summary> /// <param name="axis">The axis to handle. 0 is horizontal and 1 is vertical.</param> /// <param name="isVertical">Is this group a vertical group?</param> protected virtual void SetChildrenAlongAxis(int axis, bool isVertical) { 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); var isAxisDirty = IsAxisDirty(isVertical); bool alongOtherAxis = (isVertical ^ (axis == 1)); var defaultAnchor = GetDefaultChildAnchor(); if (alongOtherAxis) { float innerSize = size - (axis == 0 ? padding.horizontal : padding.vertical); var elements = (isAxisDirty ? (ICollection <IFastLayoutFeedback>)children : _dirtyChildren); foreach (IFastLayoutFeedback child in elements) { if (child.rectTransform == null || child.rectTransform.parent != this.transform) { return; } float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); float scaleFactor = useScale && child.rectTransform != null? child.rectTransform.localScale[axis] : 1f; Vector2 anchorMin, anchorMax; GetChildAnchors(child, axis, controlSize, childForceExpandSize, defaultAnchor, out anchorMin, out anchorMax); float requiredSpace = Mathf.Clamp(innerSize, min, flexible > 0 ? size : preferred); float startOffset = GetStartOffset(axis, requiredSpace * scaleFactor); if (controlSize) { SetChildAlongAxisWithScale(child.rectTransform, axis, startOffset, requiredSpace, scaleFactor, anchorMin, anchorMax); } else { float offsetInCell = (requiredSpace - (axis == 0? child.cachedRectWidth : child.cachedRectHeight)) * alignmentOnAxis; SetChildAlongAxisWithScale(child.rectTransform, axis, startOffset + offsetInCell, requiredSpace, scaleFactor, anchorMin, anchorMax); } } } else { float pos = (axis == 0 ? padding.left : padding.top); float itemFlexibleMultiplier = 0; float surplusSpace = size - GetTotalPreferredSize(axis); if (surplusSpace > 0) { if (GetTotalFlexibleSize(axis) == 0) { pos = GetStartOffset(axis, GetTotalPreferredSize(axis) - (axis == 0 ? padding.horizontal : padding.vertical)); } else if (GetTotalFlexibleSize(axis) > 0) { itemFlexibleMultiplier = surplusSpace / GetTotalFlexibleSize(axis); } } float minMaxLerp = 0; if (GetTotalMinSize(axis) != GetTotalPreferredSize(axis)) { minMaxLerp = Mathf.Clamp01((size - GetTotalMinSize(axis)) / (GetTotalPreferredSize(axis) - GetTotalMinSize(axis))); } int initialIndex = isAxisDirty ? 0 : Mathf.Max(0, _initialDirtyIndex); for (int i = 0; i < children.Count; i++) { IFastLayoutFeedback child = children[i]; float min, preferred, flexible; GetChildSizes(child, axis, controlSize, childForceExpandSize, out min, out preferred, out flexible); float scaleFactor = useScale && child.rectTransform != null? child.rectTransform.localScale[axis] : 1f; Vector2 anchorMin, anchorMax; GetChildAnchors(child, axis, controlSize, childForceExpandSize, defaultAnchor, out anchorMin, out anchorMax); float childSize = Mathf.Lerp(min, preferred, minMaxLerp); childSize += flexible * itemFlexibleMultiplier; if (i >= initialIndex) { if (controlSize) { SetChildAlongAxisWithScale(child.rectTransform, axis, pos, childSize, scaleFactor, anchorMin, anchorMax); } else { var sizeDelta = axis == 0 ? child.cachedRectWidth : child.cachedRectHeight; float offsetInCell = (childSize - sizeDelta) * alignmentOnAxis; SetChildAlongAxisWithScale(child.rectTransform, axis, pos + offsetInCell, childSize, scaleFactor, anchorMin, anchorMax); } } pos += childSize * scaleFactor + spacing; } } }