Skip to content

Instantly share code, notes, and snippets.

@Naxum
Last active January 2, 2016 19:21
Show Gist options
  • Save Naxum/38d49099acbab39260fc to your computer and use it in GitHub Desktop.
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…
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