Dynamic Unity UI Layout Groups

Give your layout groups some smarts. This DynamicLayoutGroup group switches orientation automatically between landscape and portrait layouts. It acts like a VerticalLayoutGroup (screenshot above) or a HorizontalLayoutGroup (screenshot below) depending the current aspect ratio of the screen.

The Why

These screenshots are from an upcoming 2.0 update to Fourtex Zen. The game shipped with a fixed landscape orientation. We recently moved to Unity 5 and decided that updating Fourtex Zen would be a good way to learn the new UI system. We wanted the game playable regardless of screen orientation. The poem panels stack the poetry text in portrait and place it side-by-side in landscape (there are 64 poems given as in-game rewards).

The Code

The DynamicLayoutGroup class inherits directly from the Unity 5 HorizontalOrVerticalLayoutGroup base class and provides a simple mechanism to determine screen orientation and shift its layout accordingly. It can be used anywhere you would normally use a VerticalLayoutGroup or HorizontalLayoutGroup.

using UnityEngine;  
using UnityEngine.UI;  
using UnityEngine.EventSystems;  
using System.Collections;  
using System.Collections.Generic;

using SDD.Extensions;  
using SDD.Events;

namespace SDD.UI {

  /// <summary>
  /// Layout group switches orientation automatically between landscape and
  /// portrait layouts so it either acts like a VerticalLayoutGroup or a
  /// HorizontalLayoutGroup.
  /// </summary>
  [AddComponentMenu("Layout/Dynamic Layout Group", 150)]
  public class DynamicLayoutGroup : HorizontalOrVerticalLayoutGroup {

    /// <summary>
    /// When is the layout vertical? In portrait or landscape?
    /// </summary>
    [SerializeField]
    public ScreenOrientation verticalWhen = ScreenOrientation.Portrait;

    public bool IsVertical { get { return GetIsVertical(); }}

    private bool GetIsVertical() {
      bool isVertical;

      if (UnityEngine.Screen.width > UnityEngine.Screen.height) {
        //orientation = ScreenOrientation.Landscape;
        isVertical = (verticalWhen == ScreenOrientation.Landscape) ? true : false;
      }
      else {
        //orientation = ScreenOrientation.Portrait;
        isVertical = (verticalWhen == ScreenOrientation.Portrait) ? true : false;
      }

      //Log.Debug(string.Format("DynamicLayoutGroup.OnRectTransformDimensionsChange() isVertical={0}a, ID={1}", isVertical, GetInstanceID()));
      return isVertical;
    }

    public override void CalculateLayoutInputHorizontal() {
      //Log.Debug(string.Format("DynamicLayoutGroup.CalculateLayoutInputHorizontal() IsVertical={0}, ID={1}", IsVertical, GetInstanceID()));

      base.CalculateLayoutInputHorizontal();
      CalcAlongAxis(0, isVertical: IsVertical);
    }

    public override void CalculateLayoutInputVertical() {
      //Log.Debug(string.Format("DynamicLayoutGroup.CalculateLayoutInputVertical() IsVertical={0}, ID={1}", IsVertical, GetInstanceID()));

      CalcAlongAxis(1, isVertical: IsVertical);
    }

    public override void SetLayoutHorizontal() {
      //Log.Debug(string.Format("DynamicLayoutGroup.SetLayoutHorizontal() IsVertical={0}, ID={1}", IsVertical, GetInstanceID()));

      SetChildrenAlongAxis(0, isVertical: IsVertical);
    }

    public override void SetLayoutVertical() {
      //Log.Debug(string.Format("DynamicLayoutGroup.SetLayoutVertical() IsVertical={0}, ID={1}", IsVertical, GetInstanceID()));

      SetChildrenAlongAxis(1, isVertical: IsVertical);
    }
  }
}
using UnityEditor;  
using UnityEngine;  
using UnityEngine.UI;

namespace SDD.UI {

  /// <summary>
  /// Override the Unity UI custom editor for HorizontalOrVerticalLayoutGroup
  /// and do exactly nothing. The only purpose of this class is to expose the
  /// public ```VerticalWhen```. The inherited editor prevents editing new
  /// publics in descendant classes without doing a full widget layout here
  /// (too much work!).
  /// </summary>
  /// <remarks>
  /// Place in ```Editor``` folder
  /// </remarks>
  [CustomEditor(typeof(SDD.UI.DynamicLayoutGroup), true)]
  [CanEditMultipleObjects]
  public class DynamicLayoutGroupEditor : UnityEditor.Editor {
  }
}
namespace SDD {

  /// <summary>
  /// Orientation of the screen regardless of which way is up
  /// </summary>
  public enum ScreenOrientation {
    Landscape,
    Portrait
  }

GitHub Gist

Author image
Coder with more gadgets that you can fit in a ten ton truck! Robert provides technical leadership and does the magic that makes the games work.
US
top