diff --git a/Scripts/Layout/FlowLayoutGroup.cs b/Scripts/Layout/FlowLayoutGroup.cs
index f8dbac5..9cf1a28 100644
--- a/Scripts/Layout/FlowLayoutGroup.cs
+++ b/Scripts/Layout/FlowLayoutGroup.cs
@@ -3,52 +3,66 @@
/// Example http://forum.unity3d.com/threads/flowlayoutgroup.296709/
/// Update by Martin Sharkbomb - http://forum.unity3d.com/threads/flowlayoutgroup.296709/#post-1977028
/// Last item alignment fix by Vicente Russo - https://bitbucket.org/ddreaper/unity-ui-extensions/issues/22/flow-layout-group-align
+/// Vertical Flow by Ramon Molossi
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
- ///
- /// Layout Group controller that arranges children in rows, fitting as many on a line until total width exceeds parent bounds
- ///
- [AddComponentMenu("Layout/Extensions/Flow Layout Group")]
+ ///
+ /// Layout Group controller that arranges children in bars, fitting as many on a line until total size exceeds parent bounds
+ ///
+ [AddComponentMenu("Layout/Extensions/Flow Layout Group")]
public class FlowLayoutGroup : LayoutGroup
{
+ public enum Axis { Horizontal = 0, Vertical = 1 }
+
public float SpacingX = 0f;
public float SpacingY = 0f;
public bool ExpandHorizontalSpacing = false;
-
+
public bool ChildForceExpandWidth = false;
public bool ChildForceExpandHeight = false;
-
+ public bool invertOrder = false;
private float _layoutHeight;
-
+ private float _layoutWidth;
+
+ [SerializeField] protected Axis m_StartAxis = Axis.Horizontal;
+ public Axis startAxis { get { return m_StartAxis; } set { SetProperty(ref m_StartAxis, value); } }
+
public override void CalculateLayoutInputHorizontal()
{
-
- base.CalculateLayoutInputHorizontal();
-
- var minWidth = GetGreatestMinimumChildWidth() + padding.left + padding.right;
-
- SetLayoutInputForAxis(minWidth, -1, -1, 0);
-
+ if (startAxis == Axis.Horizontal) {
+ base.CalculateLayoutInputHorizontal ();
+ var minWidth = GetGreatestMinimumChildWidth () + padding.left + padding.right;
+ SetLayoutInputForAxis (minWidth, -1, -1, 0);
+ } else {
+ _layoutWidth = SetLayout (0, true);
+ }
+
}
-
+
public override void SetLayoutHorizontal()
{
- SetLayout(rectTransform.rect.width, 0, false);
+ SetLayout(0, false);
}
-
+
public override void SetLayoutVertical()
{
- SetLayout(rectTransform.rect.width, 1, false);
+ SetLayout(1, false);
}
-
+
public override void CalculateLayoutInputVertical()
{
- _layoutHeight = SetLayout(rectTransform.rect.width, 1, true);
+ if (startAxis == Axis.Horizontal) {
+ _layoutHeight = SetLayout (1, true);
+ } else {
+ base.CalculateLayoutInputHorizontal ();
+ var minHeight = GetGreatestMinimumChildHeigth () + padding.bottom + padding.top;
+ SetLayoutInputForAxis (minHeight, -1, -1, 1);
+ }
}
-
+
protected bool IsCenterAlign
{
get
@@ -57,7 +71,7 @@ namespace UnityEngine.UI.Extensions
childAlignment == TextAnchor.UpperCenter;
}
}
-
+
protected bool IsRightAlign
{
get
@@ -66,7 +80,7 @@ namespace UnityEngine.UI.Extensions
childAlignment == TextAnchor.UpperRight;
}
}
-
+
protected bool IsMiddleAlign
{
get
@@ -75,7 +89,7 @@ namespace UnityEngine.UI.Extensions
childAlignment == TextAnchor.MiddleCenter;
}
}
-
+
protected bool IsLowerAlign
{
get
@@ -84,192 +98,331 @@ namespace UnityEngine.UI.Extensions
childAlignment == TextAnchor.LowerCenter;
}
}
-
+
///
- /// Holds the rects that will make up the current row being processed
+ /// Holds the rects that will make up the current bar being processed
///
- private readonly IList _rowList = new List();
-
+ private readonly IList _itemList = new List();
+
///
/// Main layout method
///
/// Width to calculate the layout with
/// 0 for horizontal axis, 1 for vertical
/// If true, sets the layout input for the axis. If false, sets child position for axis
- public float SetLayout(float width, int axis, bool layoutInput)
+ public float SetLayout(int axis, bool layoutInput)
{
+ //container height and width
var groupHeight = rectTransform.rect.height;
-
- // Width that is available after padding is subtracted
- var workingWidth = rectTransform.rect.width - padding.left - padding.right;
-
- // Accumulates the total height of the rows, including spacing and padding.
- var yOffset = IsLowerAlign ? (float)padding.bottom : (float)padding.top;
-
- var currentRowWidth = 0f;
- var currentRowHeight = 0f;
-
- for (var i = 0; i < rectChildren.Count; i++) {
-
- // LowerAlign works from back to front
- var index = IsLowerAlign ? rectChildren.Count - 1 - i : i;
-
- var child = rectChildren[index];
-
- var childWidth = LayoutUtility.GetPreferredSize(child, 0);
- var childHeight = LayoutUtility.GetPreferredSize(child, 1);
-
- // Max child width is layout group width - padding
- childWidth = Mathf.Min(childWidth, workingWidth);
-
- // If adding this element would exceed the bounds of the row,
- // go to a new line after processing the current row
- if (currentRowWidth + childWidth > workingWidth) {
-
- currentRowWidth -= SpacingX;
-
- // Process current row elements positioning
- if (!layoutInput) {
-
- var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
- LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis);
-
- }
-
- // Clear existing row
- _rowList.Clear();
-
- // Add the current row height to total height accumulator, and reset to 0 for the next row
- yOffset += currentRowHeight;
- yOffset += SpacingY;
-
- currentRowHeight = 0;
- currentRowWidth = 0;
-
+ var groupWidth = rectTransform.rect.width;
+
+ float spacingBetweenBars = 0;
+ float spacingBetweenElements = 0;
+ float offset = 0;
+ float counterOffset = 0;
+ float groupSize = 0;
+ float workingSize = 0;
+ if (startAxis == Axis.Horizontal) {
+ groupSize = groupHeight;
+ workingSize = groupWidth - padding.left - padding.right;
+ if (IsLowerAlign) {
+ offset = (float)padding.bottom;
+ counterOffset = (float)padding.top;
+ } else {
+ offset = (float)padding.top;
+ counterOffset = (float)padding.bottom;
}
-
- currentRowWidth += childWidth;
- _rowList.Add(child);
-
+ spacingBetweenBars = SpacingY;
+ spacingBetweenElements = SpacingX;
+ } else if (startAxis == Axis.Vertical) {
+ groupSize = groupWidth;
+ workingSize = groupHeight - padding.top - padding.bottom;
+ if (IsRightAlign) {
+ offset = (float)padding.right;
+ counterOffset = (float)padding.left;
+ } else {
+ offset = (float)padding.left;
+ counterOffset = (float)padding.right;
+ }
+ spacingBetweenBars = SpacingX;
+ spacingBetweenElements = SpacingY;
+ }
+
+ var currentBarSize = 0f;
+ var currentBarSpace = 0f;
+
+ for (var i = 0; i < rectChildren.Count; i++) {
+
+ int index = i;
+ var child = rectChildren [index];
+ float childSize = 0;
+ float childOtherSize = 0;
+ //get height and width of elements.
+ if (startAxis == Axis.Horizontal) {
+ if (invertOrder) {
+ index = IsLowerAlign ? rectChildren.Count - 1 - i : i;
+ }
+ child = rectChildren [index];
+ childSize = LayoutUtility.GetPreferredSize (child, 0);
+ childSize = Mathf.Min (childSize, workingSize);
+ childOtherSize = LayoutUtility.GetPreferredSize (child, 1);
+ childOtherSize = Mathf.Min (childOtherSize, workingSize);
+ } else if (startAxis == Axis.Vertical) {
+ if (invertOrder) {
+ index = IsRightAlign ? rectChildren.Count - 1 - i : i;
+ }
+ child = rectChildren [index];
+ childSize = LayoutUtility.GetPreferredSize (child, 1);
+ childSize = Mathf.Min (childSize, workingSize);
+ childOtherSize = LayoutUtility.GetPreferredSize (child, 0);
+ childOtherSize = Mathf.Min (childOtherSize, workingSize);
+ }
+
+ // If adding this element would exceed the bounds of the container,
+ // go to a new bar after processing the current bar
+ if (currentBarSize + childSize > workingSize) {
+
+ currentBarSize -= spacingBetweenElements;
+
+ // Process current bar elements positioning
+ if (!layoutInput) {
+ if (startAxis == Axis.Horizontal) {
+ float newOffset = CalculateRowVerticalOffset (groupSize, offset, currentBarSpace);
+ LayoutRow (_itemList, currentBarSize, currentBarSpace, workingSize, padding.left, newOffset, axis);
+ } else if (startAxis == Axis.Vertical) {
+ float newOffset = CalculateColHorizontalOffset (groupSize, offset, currentBarSpace);
+ LayoutCol (_itemList, currentBarSpace, currentBarSize, workingSize, newOffset, padding.top, axis);
+ }
+ }
+
+ // Clear existing bar
+ _itemList.Clear ();
+
+ // Add the current bar space to total barSpace accumulator, and reset to 0 for the next row
+ offset += currentBarSpace;
+ offset += spacingBetweenBars;
+
+ currentBarSpace = 0;
+ currentBarSize = 0;
+
+ }
+
+ currentBarSize += childSize;
+ _itemList.Add (child);
+
// We need the largest element height to determine the starting position of the next line
- if (childHeight > currentRowHeight) {
- currentRowHeight = childHeight;
+ if (childOtherSize > currentBarSpace) {
+ currentBarSpace = childOtherSize;
}
// Don't do this for the last one
- if (i < rectChildren.Count - 1 )
- currentRowWidth += SpacingX;
+ if (i < rectChildren.Count - 1){
+ currentBarSize += spacingBetweenElements;
+ }
+
}
-
+
+ // Layout the final bar
if (!layoutInput) {
- var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
- currentRowWidth -= SpacingX;
- // Layout the final row
- LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth - (_rowList.Count > 1 ? SpacingX : 0), padding.left, h, axis);
+ if (startAxis == Axis.Horizontal) {
+ float newOffset = CalculateRowVerticalOffset (groupHeight, offset, currentBarSpace);
+ currentBarSize -= spacingBetweenElements;
+ LayoutRow (_itemList, currentBarSize, currentBarSpace, workingSize - (ChildForceExpandWidth ? 0 : spacingBetweenElements), padding.left, newOffset, axis);
+ }else if (startAxis == Axis.Vertical) {
+ float newOffset = CalculateColHorizontalOffset(groupWidth, offset, currentBarSpace);
+ currentBarSize -= spacingBetweenElements;
+ LayoutCol(_itemList, currentBarSpace, currentBarSize, workingSize - (ChildForceExpandHeight ? 0 : spacingBetweenElements), newOffset, padding.top, axis);
+ }
}
-
- _rowList.Clear();
-
- // Add the last rows height to the height accumulator
- yOffset += currentRowHeight;
- yOffset += IsLowerAlign ? padding.top : padding.bottom;
-
+
+ _itemList.Clear();
+
+ // Add the last bar space to the barSpace accumulator
+ offset += currentBarSpace;
+ offset += counterOffset;
+
if (layoutInput) {
-
- if(axis == 1)
- SetLayoutInputForAxis(yOffset, yOffset, -1, axis);
-
+ SetLayoutInputForAxis(offset, offset, -1, axis);
}
-
- return yOffset;
+ return offset;
}
-
+
private float CalculateRowVerticalOffset(float groupHeight, float yOffset, float currentRowHeight)
{
- float h;
-
if (IsLowerAlign) {
- h = groupHeight - yOffset - currentRowHeight;
+ return groupHeight - yOffset - currentRowHeight;
} else if (IsMiddleAlign) {
- h = groupHeight*0.5f - _layoutHeight * 0.5f + yOffset;
+ return groupHeight * 0.5f - _layoutHeight * 0.5f + yOffset;
} else {
- h = yOffset;
+ return yOffset;
}
- return h;
}
-
+
+ private float CalculateColHorizontalOffset(float groupWidth, float xOffset, float currentColWidth)
+ {
+ if (IsRightAlign) {
+ return groupWidth - xOffset - currentColWidth;
+ } else if (IsCenterAlign) {
+ return groupWidth * 0.5f - _layoutWidth * 0.5f + xOffset;
+ } else {
+ return xOffset;
+ }
+ }
+
protected void LayoutRow(IList contents, float rowWidth, float rowHeight, float maxWidth, float xOffset, float yOffset, int axis)
{
var xPos = xOffset;
-
- if (!ChildForceExpandWidth && IsCenterAlign)
+
+ if (!ChildForceExpandWidth && IsCenterAlign) {
xPos += (maxWidth - rowWidth) * 0.5f;
- else if (!ChildForceExpandWidth && IsRightAlign)
+ } else if (!ChildForceExpandWidth && IsRightAlign) {
xPos += (maxWidth - rowWidth);
-
+ }
+
var extraWidth = 0f;
var extraSpacing = 0f;
if (ChildForceExpandWidth) {
- extraWidth = (maxWidth - rowWidth)/_rowList.Count;
+ extraWidth = (maxWidth - rowWidth)/_itemList.Count;
}
else if (ExpandHorizontalSpacing) {
- extraSpacing = (maxWidth - rowWidth)/(_rowList.Count - 1);
- if (_rowList.Count > 1) {
- if (IsCenterAlign)
- xPos -= extraSpacing * 0.5f * (_rowList.Count - 1);
- else if (IsRightAlign)
- xPos -= extraSpacing * (_rowList.Count - 1);
+ extraSpacing = (maxWidth - rowWidth)/(_itemList.Count - 1);
+ if (_itemList.Count > 1) {
+ if (IsCenterAlign) {
+ xPos -= extraSpacing * 0.5f * (_itemList.Count - 1);
+ } else if (IsRightAlign) {
+ xPos -= extraSpacing * (_itemList.Count - 1);
+ }
}
}
-
- for (var j = 0; j < _rowList.Count; j++) {
-
- var index = IsLowerAlign ? _rowList.Count - 1 - j : j;
-
- var rowChild = _rowList[index];
-
+
+ for (var j = 0; j < _itemList.Count; j++) {
+
+ var index = IsLowerAlign ? _itemList.Count - 1 - j : j;
+
+ var rowChild = _itemList[index];
+
var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0) + extraWidth;
var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1);
-
+
if (ChildForceExpandHeight)
rowChildHeight = rowHeight;
-
+
rowChildWidth = Mathf.Min(rowChildWidth, maxWidth);
-
+
var yPos = yOffset;
- if (IsMiddleAlign)
+ if (IsMiddleAlign) {
yPos += (rowHeight - rowChildHeight) * 0.5f;
- else if (IsLowerAlign)
+ } else if (IsLowerAlign) {
yPos += (rowHeight - rowChildHeight);
+ }
- //
- if (ExpandHorizontalSpacing && j > 0)
+ if (ExpandHorizontalSpacing && j > 0) {
xPos += extraSpacing;
+ }
- if (axis == 0)
- SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth);
- else
- SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight);
+ if (axis == 0) {
+ SetChildAlongAxis (rowChild, 0, xPos, rowChildWidth);
+ } else {
+ SetChildAlongAxis (rowChild, 1, yPos, rowChildHeight);
+ }
// Don't do horizontal spacing for the last one
- if (j < _rowList.Count - 1 )
+ if (j < _itemList.Count - 1) {
xPos += rowChildWidth + SpacingX;
+ }
}
}
-
+
+ protected void LayoutCol(IList contents, float colWidth, float colHeight, float maxHeight, float xOffset, float yOffset, int axis)
+ {
+ var yPos = yOffset;
+
+ if (!ChildForceExpandHeight && IsMiddleAlign) {
+ yPos += (maxHeight - colHeight) * 0.5f;
+ } else if (!ChildForceExpandHeight && IsLowerAlign) {
+ yPos += (maxHeight - colHeight);
+ }
+
+ var extraHeight = 0f;
+ var extraSpacing = 0f;
+
+ if (ChildForceExpandHeight) {
+ extraHeight = (maxHeight - colHeight)/_itemList.Count;
+ }
+ else if (ExpandHorizontalSpacing) {
+ extraSpacing = (maxHeight - colHeight)/(_itemList.Count - 1);
+ if (_itemList.Count > 1) {
+ if (IsMiddleAlign) {
+ yPos -= extraSpacing * 0.5f * (_itemList.Count - 1);
+ } else if (IsLowerAlign) {
+ yPos -= extraSpacing * (_itemList.Count - 1);
+ }
+ }
+ }
+
+ for (var j = 0; j < _itemList.Count; j++) {
+
+ var index = IsRightAlign ? _itemList.Count - 1 - j : j;
+
+ var rowChild = _itemList[index];
+
+ var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0) ;
+ var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1) + extraHeight;
+
+ if (ChildForceExpandWidth) {
+ rowChildWidth = colWidth;
+ }
+
+ rowChildHeight = Mathf.Min(rowChildHeight, maxHeight);
+
+ var xPos = xOffset;
+
+ if (IsCenterAlign) {
+ xPos += (colWidth - rowChildWidth) * 0.5f;
+ } else if (IsRightAlign) {
+ xPos += (colWidth - rowChildWidth);
+ }
+
+ //
+ if (ExpandHorizontalSpacing && j > 0) {
+ yPos += extraSpacing;
+ }
+
+ if (axis == 0) {
+ SetChildAlongAxis (rowChild, 0, xPos, rowChildWidth);
+ } else {
+ SetChildAlongAxis (rowChild, 1, yPos, rowChildHeight);
+ }
+
+ // Don't do vertical spacing for the last one
+ if (j < _itemList.Count - 1) {
+ yPos += rowChildHeight + SpacingY;
+ }
+ }
+ }
+
public float GetGreatestMinimumChildWidth()
{
var max = 0f;
-
for (var i = 0; i < rectChildren.Count; i++) {
var w = LayoutUtility.GetMinWidth(rectChildren[i]);
-
+
+ max = Mathf.Max(w, max);
+ }
+ return max;
+ }
+
+ public float GetGreatestMinimumChildHeigth()
+ {
+ var max = 0f;
+ for (var i = 0; i < rectChildren.Count; i++) {
+ var w = LayoutUtility.GetMinHeight(rectChildren[i]);
+
max = Mathf.Max(w, max);
}
-
return max;
}
}
-}
+}
\ No newline at end of file