Last active
January 2, 2016 19:21
-
-
Save Naxum/38d49099acbab39260fc to your computer and use it in GitHub Desktop.
http://i.imgur.com/q9KqufZ.png Replacement for Horizontal or VerticalLayoutGroups in Unity when switching direction on orientation/screen size changes. It took a while to get the code to a stable point that also includes basic features like layout, padding, and spacing. Feel free to use however you like, but if you notice a bug or have an improv…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using UnityEngine; | |
using UnityEngine.UI; | |
using System.Collections; | |
using System.Collections.Generic; | |
public class ResponsiveLayoutGroup : LayoutGroup { | |
[Tooltip("Use this to flip which axis should be used in each orientation")] | |
public bool reverseLayout; | |
public Vector2 spacing = Vector2.zero; | |
List<RectTransform> activeChildren = new List<RectTransform>(); | |
public override void CalculateLayoutInputHorizontal () { | |
SetSize(Axis.Horizontal); | |
} | |
public override void CalculateLayoutInputVertical () { | |
SetSize(Axis.Vertical); | |
} | |
public override void SetLayoutHorizontal () { | |
LayoutChildren(Axis.Horizontal); | |
} | |
public override void SetLayoutVertical () { | |
LayoutChildren(Axis.Vertical); | |
} | |
Axis GetDirectionAxis() { | |
var result = reverseLayout ? Screen.width > Screen.height : Screen.width < Screen.height; | |
return result ? Axis.Vertical : Axis.Horizontal; | |
} | |
void SetSize(Axis axis) { | |
RefreshActiveChildrenParticipatingInLayout(); | |
float totalMin = 0, totalPreferred = 0, totalFlexible = 0; | |
if(axis == GetDirectionAxis()) { | |
GetCumulativeSizesInChildren(axis, ref totalMin, ref totalPreferred, ref totalFlexible); | |
} else { | |
GetMaximumSizesInChildren(axis, ref totalMin, ref totalPreferred, ref totalFlexible); | |
} | |
base.SetLayoutInputForAxis(totalMin, totalPreferred, totalFlexible, (int)axis); | |
} | |
void GetCumulativeSizesInChildren(Axis axis, ref float totalMin, ref float totalPreferred, ref float totalFlexible) { | |
var baseAmount = axis == Axis.Horizontal ? padding.horizontal : padding.vertical; | |
var space = (axis == Axis.Vertical ? spacing.y : spacing.x); | |
totalMin = baseAmount; | |
totalPreferred = baseAmount; | |
totalFlexible = baseAmount; | |
foreach(RectTransform child in activeChildren) { | |
var min = LayoutUtility.GetMinSize(child, (int)axis); | |
var pref = LayoutUtility.GetPreferredSize(child, (int)axis); | |
var flex = LayoutUtility.GetFlexibleSize(child, (int)axis); | |
totalMin += min; | |
totalPreferred += pref; | |
totalFlexible += flex; | |
} | |
totalMin += space * (activeChildren.Count - 1); | |
totalPreferred += space * (activeChildren.Count - 1); | |
} | |
void GetMaximumSizesInChildren(Axis axis, ref float totalMin, ref float totalPreferred, ref float totalFlexible) { | |
var baseAmount = axis == Axis.Horizontal ? padding.horizontal : padding.vertical; | |
var space = GetDirectionAxis() == axis ? (axis == Axis.Vertical ? spacing.y : spacing.x) : 0; | |
totalMin = 0; | |
totalPreferred = 0; | |
totalFlexible = 0; | |
foreach(RectTransform child in activeChildren) { | |
var min = LayoutUtility.GetMinSize(child, (int)axis) + space; | |
var pref = LayoutUtility.GetPreferredSize(child, (int)axis) + space; | |
var flex = LayoutUtility.GetFlexibleSize(child, (int)axis); | |
if(min > totalMin) totalMin = min; | |
if(pref > totalPreferred) totalPreferred = pref; | |
if(flex > totalFlexible) totalFlexible = flex; | |
} | |
totalMin += baseAmount; | |
totalPreferred += baseAmount; | |
totalFlexible += baseAmount; | |
} | |
void RefreshActiveChildrenParticipatingInLayout() { | |
activeChildren.Clear(); | |
foreach(RectTransform child in rectTransform) { | |
if(!child.gameObject.activeInHierarchy) continue; | |
var layoutElement = child.GetComponent<LayoutElement>(); | |
if(layoutElement != null && layoutElement.ignoreLayout) continue; | |
activeChildren.Add(child); | |
} | |
} | |
float GetTotalFlexibleSize(Axis axis) { | |
var result = 0f; | |
foreach(RectTransform child in activeChildren) { | |
result += LayoutUtility.GetFlexibleSize(child, (int)axis); | |
} | |
return result; | |
} | |
float GetAvailableContentSize(Axis axis) { | |
var space = (axis == Axis.Horizontal ? spacing.x : spacing.y) * (activeChildren.Count-1); | |
if(GetDirectionAxis() != axis) { | |
space = 0; | |
} | |
if(axis == Axis.Horizontal) { | |
return rectTransform.rect.width - padding.horizontal - space; | |
} else { | |
return rectTransform.rect.height - padding.vertical - space; | |
} | |
} | |
float GetLeftoverSize(Axis axis) { | |
var result = 0f; | |
foreach(RectTransform child in activeChildren) { | |
result += LayoutUtility.GetPreferredSize(child, (int)axis); | |
} | |
return GetAvailableContentSize(axis) - result; | |
} | |
void LayoutChildren(Axis axis) { | |
RefreshActiveChildrenParticipatingInLayout(); | |
if(activeChildren.Count == 0) return; | |
float fullLayoutSize = GetAvailableContentSize(axis); | |
float currentPos = axis == Axis.Horizontal ? padding.left : padding.top; //for top left thing | |
var directionAxis = GetDirectionAxis(); | |
var totalFlexible = GetTotalFlexibleSize(axis); | |
var totalLeftover = GetLeftoverSize(axis); | |
var totalContentFinalSize = 0f; | |
var childFinalSizes = new Dictionary<RectTransform, float>(); | |
foreach(var child in activeChildren) { | |
var childSize = LayoutUtility.GetPreferredSize(child, (int)axis); | |
var flex = (LayoutUtility.GetFlexibleSize(child, (int)axis) / totalFlexible) * totalLeftover; | |
if(flex > 0) childSize += flex; | |
if(axis != directionAxis) { | |
childSize = fullLayoutSize; | |
} | |
childFinalSizes.Add(child, childSize); | |
totalContentFinalSize += childSize; | |
} | |
if(axis != directionAxis) { | |
totalContentFinalSize += (activeChildren.Count - 1) * (axis == Axis.Horizontal ? spacing.x : spacing.y); | |
} | |
var finalContentSizeLeftOver = fullLayoutSize - totalContentFinalSize; | |
if(axis == Axis.Vertical && axis == GetDirectionAxis()) { | |
if(childAlignment == TextAnchor.MiddleCenter || childAlignment == TextAnchor.MiddleLeft || childAlignment == TextAnchor.MiddleRight) { | |
//middle | |
currentPos += finalContentSizeLeftOver * 0.5f; | |
} else if (childAlignment == TextAnchor.LowerCenter || childAlignment == TextAnchor.LowerLeft || childAlignment == TextAnchor.LowerRight) { | |
//lower | |
currentPos += finalContentSizeLeftOver; | |
} | |
} else if(axis == Axis.Horizontal && axis == GetDirectionAxis()) { | |
if(childAlignment == TextAnchor.LowerCenter || childAlignment == TextAnchor.MiddleCenter || childAlignment == TextAnchor.UpperCenter) { | |
//middle | |
currentPos += finalContentSizeLeftOver * 0.5f; | |
} else if (childAlignment == TextAnchor.LowerRight || childAlignment == TextAnchor.MiddleRight || childAlignment == TextAnchor.UpperRight) { | |
//right | |
currentPos += finalContentSizeLeftOver; | |
} | |
} | |
foreach(RectTransform child in activeChildren) { | |
base.SetChildAlongAxis(child, (int)axis, currentPos, childFinalSizes[child]); | |
if(axis == directionAxis) { | |
currentPos += axis == Axis.Vertical ? child.rect.height + spacing.y : child.rect.width + spacing.x; | |
} | |
LayoutRebuilder.MarkLayoutForRebuild(child); | |
} | |
} | |
} | |
enum Axis { | |
Horizontal, | |
Vertical | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment