2015-02-10 08:03:38 +08:00
|
|
|
/// Credit Simie
|
|
|
|
/// Sourced from - http://forum.unity3d.com/threads/flowlayoutgroup.296709/
|
|
|
|
/// Example http://forum.unity3d.com/threads/flowlayoutgroup.296709/
|
2015-09-20 07:24:17 +08:00
|
|
|
/// 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
|
2015-02-10 08:03:38 +08:00
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
namespace UnityEngine.UI.Extensions
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Layout Group controller that arranges children in rows, fitting as many on a line until total width exceeds parent bounds
|
|
|
|
/// </summary>
|
2015-02-11 04:56:12 +08:00
|
|
|
[AddComponentMenu("Layout/Extensions/Flow Layout Group")]
|
2015-02-10 08:03:38 +08:00
|
|
|
public class FlowLayoutGroup : LayoutGroup
|
|
|
|
{
|
2015-09-20 07:24:17 +08:00
|
|
|
public float SpacingX = 0f;
|
|
|
|
public float SpacingY = 0f;
|
|
|
|
public bool ExpandHorizontalSpacing = false;
|
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public bool ChildForceExpandWidth = false;
|
|
|
|
public bool ChildForceExpandHeight = false;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
private float _layoutHeight;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public override void CalculateLayoutInputHorizontal()
|
|
|
|
{
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
base.CalculateLayoutInputHorizontal();
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var minWidth = GetGreatestMinimumChildWidth() + padding.left + padding.right;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
SetLayoutInputForAxis(minWidth, -1, -1, 0);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public override void SetLayoutHorizontal()
|
|
|
|
{
|
|
|
|
SetLayout(rectTransform.rect.width, 0, false);
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public override void SetLayoutVertical()
|
|
|
|
{
|
|
|
|
SetLayout(rectTransform.rect.width, 1, false);
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public override void CalculateLayoutInputVertical()
|
|
|
|
{
|
|
|
|
_layoutHeight = SetLayout(rectTransform.rect.width, 1, true);
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
protected bool IsCenterAlign
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return childAlignment == TextAnchor.LowerCenter || childAlignment == TextAnchor.MiddleCenter ||
|
2015-09-20 07:24:17 +08:00
|
|
|
childAlignment == TextAnchor.UpperCenter;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
protected bool IsRightAlign
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return childAlignment == TextAnchor.LowerRight || childAlignment == TextAnchor.MiddleRight ||
|
2015-09-20 07:24:17 +08:00
|
|
|
childAlignment == TextAnchor.UpperRight;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
protected bool IsMiddleAlign
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return childAlignment == TextAnchor.MiddleLeft || childAlignment == TextAnchor.MiddleRight ||
|
2015-09-20 07:24:17 +08:00
|
|
|
childAlignment == TextAnchor.MiddleCenter;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
protected bool IsLowerAlign
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return childAlignment == TextAnchor.LowerLeft || childAlignment == TextAnchor.LowerRight ||
|
2015-09-20 07:24:17 +08:00
|
|
|
childAlignment == TextAnchor.LowerCenter;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Holds the rects that will make up the current row being processed
|
|
|
|
/// </summary>
|
|
|
|
private readonly IList<RectTransform> _rowList = new List<RectTransform>();
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Main layout method
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="width">Width to calculate the layout with</param>
|
|
|
|
/// <param name="axis">0 for horizontal axis, 1 for vertical</param>
|
|
|
|
/// <param name="layoutInput">If true, sets the layout input for the axis. If false, sets child position for axis</param>
|
|
|
|
public float SetLayout(float width, int axis, bool layoutInput)
|
|
|
|
{
|
|
|
|
var groupHeight = rectTransform.rect.height;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Width that is available after padding is subtracted
|
|
|
|
var workingWidth = rectTransform.rect.width - padding.left - padding.right;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Accumulates the total height of the rows, including spacing and padding.
|
|
|
|
var yOffset = IsLowerAlign ? (float)padding.bottom : (float)padding.top;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var currentRowWidth = 0f;
|
|
|
|
var currentRowHeight = 0f;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
for (var i = 0; i < rectChildren.Count; i++) {
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// LowerAlign works from back to front
|
|
|
|
var index = IsLowerAlign ? rectChildren.Count - 1 - i : i;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var child = rectChildren[index];
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var childWidth = LayoutUtility.GetPreferredSize(child, 0);
|
|
|
|
var childHeight = LayoutUtility.GetPreferredSize(child, 1);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
|
|
|
// Max child width is layout group width - padding
|
2015-02-10 08:03:38 +08:00
|
|
|
childWidth = Mathf.Min(childWidth, workingWidth);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// 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) {
|
2015-09-20 07:24:17 +08:00
|
|
|
|
|
|
|
currentRowWidth -= SpacingX;
|
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Process current row elements positioning
|
|
|
|
if (!layoutInput) {
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
|
|
|
|
LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth, padding.left, h, axis);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Clear existing row
|
|
|
|
_rowList.Clear();
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Add the current row height to total height accumulator, and reset to 0 for the next row
|
|
|
|
yOffset += currentRowHeight;
|
2015-09-20 07:24:17 +08:00
|
|
|
yOffset += SpacingY;
|
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
currentRowHeight = 0;
|
|
|
|
currentRowWidth = 0;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
currentRowWidth += childWidth;
|
|
|
|
_rowList.Add(child);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// We need the largest element height to determine the starting position of the next line
|
|
|
|
if (childHeight > currentRowHeight) {
|
|
|
|
currentRowHeight = childHeight;
|
|
|
|
}
|
|
|
|
|
2015-09-20 07:24:17 +08:00
|
|
|
// Don't do this for the last one
|
|
|
|
if (i < rectChildren.Count - 1 )
|
|
|
|
currentRowWidth += SpacingX;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (!layoutInput) {
|
|
|
|
var h = CalculateRowVerticalOffset(groupHeight, yOffset, currentRowHeight);
|
2015-09-20 07:24:17 +08:00
|
|
|
currentRowWidth -= SpacingX;
|
2015-02-10 08:03:38 +08:00
|
|
|
// Layout the final row
|
2015-10-02 02:29:58 +08:00
|
|
|
LayoutRow(_rowList, currentRowWidth, currentRowHeight, workingWidth - (_rowList.Count > 1 ? SpacingX : 0), padding.left, h, axis);
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
_rowList.Clear();
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
// Add the last rows height to the height accumulator
|
|
|
|
yOffset += currentRowHeight;
|
|
|
|
yOffset += IsLowerAlign ? padding.top : padding.bottom;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (layoutInput) {
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if(axis == 1)
|
|
|
|
SetLayoutInputForAxis(yOffset, yOffset, -1, axis);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
return yOffset;
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
private float CalculateRowVerticalOffset(float groupHeight, float yOffset, float currentRowHeight)
|
|
|
|
{
|
|
|
|
float h;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (IsLowerAlign) {
|
|
|
|
h = groupHeight - yOffset - currentRowHeight;
|
|
|
|
} else if (IsMiddleAlign) {
|
|
|
|
h = groupHeight*0.5f - _layoutHeight * 0.5f + yOffset;
|
|
|
|
} else {
|
|
|
|
h = yOffset;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
protected void LayoutRow(IList<RectTransform> contents, float rowWidth, float rowHeight, float maxWidth, float xOffset, float yOffset, int axis)
|
|
|
|
{
|
|
|
|
var xPos = xOffset;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (!ChildForceExpandWidth && IsCenterAlign)
|
|
|
|
xPos += (maxWidth - rowWidth) * 0.5f;
|
|
|
|
else if (!ChildForceExpandWidth && IsRightAlign)
|
|
|
|
xPos += (maxWidth - rowWidth);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var extraWidth = 0f;
|
2015-09-20 07:24:17 +08:00
|
|
|
var extraSpacing = 0f;
|
2015-02-10 08:03:38 +08:00
|
|
|
|
|
|
|
if (ChildForceExpandWidth) {
|
|
|
|
extraWidth = (maxWidth - rowWidth)/_rowList.Count;
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
for (var j = 0; j < _rowList.Count; j++) {
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var index = IsLowerAlign ? _rowList.Count - 1 - j : j;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var rowChild = _rowList[index];
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var rowChildWidth = LayoutUtility.GetPreferredSize(rowChild, 0) + extraWidth;
|
|
|
|
var rowChildHeight = LayoutUtility.GetPreferredSize(rowChild, 1);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (ChildForceExpandHeight)
|
|
|
|
rowChildHeight = rowHeight;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
rowChildWidth = Mathf.Min(rowChildWidth, maxWidth);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
var yPos = yOffset;
|
|
|
|
|
|
|
|
if (IsMiddleAlign)
|
|
|
|
yPos += (rowHeight - rowChildHeight) * 0.5f;
|
|
|
|
else if (IsLowerAlign)
|
|
|
|
yPos += (rowHeight - rowChildHeight);
|
|
|
|
|
2015-09-20 07:24:17 +08:00
|
|
|
//
|
|
|
|
if (ExpandHorizontalSpacing && j > 0)
|
|
|
|
xPos += extraSpacing;
|
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
if (axis == 0)
|
|
|
|
SetChildAlongAxis(rowChild, 0, xPos, rowChildWidth);
|
|
|
|
else
|
|
|
|
SetChildAlongAxis(rowChild, 1, yPos, rowChildHeight);
|
|
|
|
|
2015-09-20 07:24:17 +08:00
|
|
|
// Don't do horizontal spacing for the last one
|
|
|
|
if (j < _rowList.Count - 1 )
|
|
|
|
xPos += rowChildWidth + SpacingX;
|
2015-02-10 08:03:38 +08:00
|
|
|
}
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
public float GetGreatestMinimumChildWidth()
|
|
|
|
{
|
|
|
|
var max = 0f;
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
for (var i = 0; i < rectChildren.Count; i++) {
|
|
|
|
var w = LayoutUtility.GetMinWidth(rectChildren[i]);
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
max = Mathf.Max(w, max);
|
|
|
|
}
|
2015-09-20 07:24:17 +08:00
|
|
|
|
2015-02-10 08:03:38 +08:00
|
|
|
return max;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|