Skip to content

Instantly share code, notes, and snippets.

@QuantumCalzone
Last active April 1, 2021 23:08
Show Gist options
  • Save QuantumCalzone/ce5e6b1421203fdaa1a75b89afc39cbc to your computer and use it in GitHub Desktop.
Save QuantumCalzone/ce5e6b1421203fdaa1a75b89afc39cbc to your computer and use it in GitHub Desktop.
An extension of Unity's LayoutElement script that enable more flexible adaptation such as matching another RecTransform's dimensions or setting maximum preferred values. Put the Inspector and Property Drawer scripts in an Editor folder. Also available as a package at https://github.com/QuantumCalzone/UnityLayoutElementExtended
using UnityEngine;
using UnityEngine.UI;
namespace QuantumCalzone
{
[AddComponentMenu("Layout/Extended/Layout Element Extended")]
[RequireComponent(typeof(RectTransform))]
public class LayoutElementExtended : LayoutElement
{
public LayoutElementExtendedValue MinWidthExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue MinHeightExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue PreferredWidthExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue PreferredHeightExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue FlexibleWidthExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue FlexibleHeightExtended = new LayoutElementExtendedValue();
public LayoutElementExtendedValue MaxWidth = new LayoutElementExtendedValue();
public LayoutElementExtendedValue MaxHeight = new LayoutElementExtendedValue();
private RectTransform rectTransform = null;
public RectTransform GetRectTransform {
get {
if (!rectTransform) rectTransform = GetComponent<RectTransform>();
return rectTransform;
}
}
public float Width {
get {
var valueToReturn = 0f;
if (MinWidthExtended.Enabled && !PreferredWidthExtended.Enabled)
{
valueToReturn = MinWidth;
}
else if (!MinWidthExtended.Enabled && PreferredWidthExtended.Enabled)
{
valueToReturn = PreferredWidth;
}
else if (MinWidthExtended.Enabled && PreferredWidthExtended.Enabled)
{
valueToReturn = PreferredWidth > MinWidth ? PreferredWidth : MinWidth;
}
return valueToReturn;
}
}
public float Height {
get {
var valueToReturn = 0f;
if (MinHeightExtended.Enabled && !PreferredHeightExtended.Enabled)
{
valueToReturn = MinHeight;
}
else if (!MinHeightExtended.Enabled && PreferredHeightExtended.Enabled)
{
valueToReturn = PreferredHeight;
}
else if (MinHeightExtended.Enabled && PreferredHeightExtended.Enabled)
{
valueToReturn = PreferredHeight > MinHeight ? PreferredHeight : MinHeight;
}
return valueToReturn;
}
}
#region Min
private float MinWidth {
get {
var valueToReturn = 0f;
if (MinWidthExtended.Enabled)
{
MinWidthExtended.ProcessTargetValue(gameObject);
valueToReturn = MinWidthExtended.TargetValue;
if (MaxWidth.Enabled)
{
MaxWidth.ProcessTargetValue(gameObject);
if (valueToReturn > MaxWidth.TargetValue)
valueToReturn = MaxWidth.TargetValue;
}
}
return valueToReturn;
}
}
private float MinHeight {
get {
var valueToReturn = 0f;
if (MinHeightExtended.Enabled)
{
MinHeightExtended.ProcessTargetValue(gameObject);
valueToReturn = MinHeightExtended.TargetValue;
if (MaxHeight.Enabled)
{
MaxHeight.ProcessTargetValue(gameObject);
if (valueToReturn > MaxHeight.TargetValue)
valueToReturn = MaxHeight.TargetValue;
}
}
return valueToReturn;
}
}
#endregion
#region Preferred
private float PreferredWidth {
get {
var preferredWidth = 0f;
if (PreferredWidthExtended.Enabled)
{
PreferredWidthExtended.ProcessTargetValue(gameObject);
preferredWidth = PreferredWidthExtended.TargetValue;
if (MaxWidth.Enabled)
{
MaxWidth.ProcessTargetValue(gameObject);
if (preferredWidth > MaxWidth.TargetValue)
preferredWidth = MaxWidth.TargetValue;
}
}
return preferredWidth;
}
}
private float PreferredHeight {
get {
var preferredHeight = 0f;
if (PreferredHeightExtended.Enabled)
{
PreferredHeightExtended.ProcessTargetValue(gameObject);
preferredHeight = PreferredHeightExtended.TargetValue;
if (MaxHeight.Enabled)
{
MaxHeight.ProcessTargetValue(gameObject);
if (preferredHeight > MaxHeight.TargetValue)
preferredHeight = MaxHeight.TargetValue;
}
}
return preferredHeight;
}
}
#endregion
#region Flexible
private float FlexibleWidth {
get {
var flexibleWidth = 0f;
if (FlexibleWidthExtended.Enabled)
{
FlexibleWidthExtended.ProcessTargetValue(gameObject);
flexibleWidth = FlexibleWidthExtended.TargetValue;
}
return flexibleWidth;
}
}
private float FlexibleHeight {
get {
var flexibleHeight = 0f;
if (FlexibleHeightExtended.Enabled)
{
FlexibleHeightExtended.ProcessTargetValue(gameObject);
flexibleHeight = FlexibleHeightExtended.TargetValue;
}
return flexibleHeight;
}
}
#endregion
#region Unity Methods
public override void CalculateLayoutInputHorizontal()
{
minWidth = MinWidthExtended.Enabled ? MinWidth : -1;
preferredWidth = PreferredWidthExtended.Enabled ? PreferredWidth : -1;
flexibleWidth = FlexibleWidthExtended.Enabled ? FlexibleWidth : -1;
base.CalculateLayoutInputHorizontal();
}
public override void CalculateLayoutInputVertical()
{
minHeight = MinHeightExtended.Enabled ? MinHeight : -1;
preferredHeight = PreferredHeightExtended.Enabled ? PreferredHeight : -1;
flexibleHeight = FlexibleHeightExtended.Enabled ? FlexibleHeight : -1;
base.CalculateLayoutInputVertical();
}
#if UNITY_EDITOR
private void Update()
{
CalculateLayoutInputHorizontal();
CalculateLayoutInputVertical();
}
#endif
#endregion
}
}
using UnityEditor;
using UnityEditor.UI;
namespace QuantumCalzone
{
[CanEditMultipleObjects]
[CustomEditor(typeof(LayoutElementExtended), true)]
public class LayoutElementExtendedEditor : LayoutElementEditor
{
private SerializedProperty m_IgnoreLayout = null;
private SerializedProperty m_LayoutPriority = null;
private SerializedProperty MinWidthExtended = null;
private SerializedProperty MinHeightExtended = null;
private SerializedProperty PreferredWidthExtended = null;
private SerializedProperty PreferredHeightExtended = null;
private SerializedProperty FlexibleWidthExtended = null;
private SerializedProperty FlexibleHeightExtended = null;
private SerializedProperty MaxWidth = null;
private SerializedProperty MaxHeight = null;
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(m_IgnoreLayout);
if (!m_IgnoreLayout.boolValue)
{
EditorGUILayout.BeginVertical("Box");
EditorGUILayout.LabelField("Extended", EditorStyles.boldLabel);
DisplayPropertyFieldInBox(MinWidthExtended);
DisplayPropertyFieldInBox(MinHeightExtended);
DisplayPropertyFieldInBox(PreferredWidthExtended);
DisplayPropertyFieldInBox(PreferredHeightExtended);
DisplayPropertyFieldInBox(FlexibleWidthExtended);
DisplayPropertyFieldInBox(FlexibleHeightExtended);
DisplayPropertyFieldInBox(MaxWidth);
DisplayPropertyFieldInBox(MaxHeight);
EditorGUILayout.EndVertical();
}
EditorGUILayout.PropertyField(m_LayoutPriority);
serializedObject.ApplyModifiedProperties();
}
protected override void OnEnable()
{
base.OnEnable();
m_IgnoreLayout = serializedObject.FindProperty("m_IgnoreLayout");
m_LayoutPriority = serializedObject.FindProperty("m_LayoutPriority");
MinWidthExtended = serializedObject.FindProperty("MinWidthExtended");
MinHeightExtended = serializedObject.FindProperty("MinHeightExtended");
PreferredWidthExtended = serializedObject.FindProperty("PreferredWidthExtended");
PreferredHeightExtended = serializedObject.FindProperty("PreferredHeightExtended");
FlexibleWidthExtended = serializedObject.FindProperty("FlexibleWidthExtended");
FlexibleHeightExtended = serializedObject.FindProperty("FlexibleHeightExtended");
MaxWidth = serializedObject.FindProperty("MaxWidth");
MaxHeight = serializedObject.FindProperty("MaxHeight");
}
private void DisplayPropertyFieldInBox(SerializedProperty target)
{
EditorGUILayout.BeginVertical("Box");
EditorGUILayout.PropertyField(target);
EditorGUILayout.EndVertical();
}
}
}
using System;
using UnityEngine;
namespace QuantumCalzone
{
[Serializable]
public class LayoutElementExtendedValue
{
public enum ReferenceTypes { None, Width, Height }
public bool Enabled = false;
public ReferenceTypes ReferenceType = ReferenceTypes.None;
public RectTransform Reference = null;
public float ReferenceDelta = 0;
public float TargetValue = 0;
public void ProcessTargetValue(UnityEngine.Object context)
{
if (!Reference && ReferenceType != ReferenceTypes.None)
{
Debug.Log("This needs a reference to process your target Layout values", context);
return;
}
switch (ReferenceType)
{
case ReferenceTypes.None:
break;
case ReferenceTypes.Width:
TargetValue = Reference.rect.width;
break;
case ReferenceTypes.Height:
TargetValue = Reference.rect.height;
break;
default:
Debug.LogError(string.Format("No support for a referenceType of: {0}", ReferenceType), context);
break;
}
TargetValue += ReferenceDelta;
}
}
}
using UnityEngine;
using UnityEditor;
namespace QuantumCalzone
{
[CustomPropertyDrawer(typeof(LayoutElementExtendedValue))]
public class LayoutElementExtendedValuePropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
GUI.Label(position, label, EditorStyles.boldLabel);
var enabled = property.FindPropertyRelative("Enabled");
EditorGUILayout.PropertyField(enabled);
if (enabled.boolValue)
{
var referenceType = property.FindPropertyRelative("ReferenceType");
var reference = property.FindPropertyRelative("Reference");
var referenceDelta = property.FindPropertyRelative("ReferenceDelta");
var targetValue = property.FindPropertyRelative("TargetValue");
EditorGUILayout.PropertyField(referenceType);
if ((LayoutElementExtendedValue.ReferenceTypes)referenceType.enumValueIndex != LayoutElementExtendedValue.ReferenceTypes.None)
{
EditorGUILayout.PropertyField(reference);
EditorGUILayout.PropertyField(referenceDelta);
GUI.enabled = false;
EditorGUILayout.PropertyField(targetValue);
GUI.enabled = true;
}
else EditorGUILayout.PropertyField(targetValue);
}
EditorGUI.EndProperty();
}
}
}
@GroktIO
Copy link

GroktIO commented Feb 16, 2020

This stuff is golden, ought to be built into unity. For those who use this, the "DisplayPropertyFieldInBox()" methods seem to be missing, just replace with standard unity ui logic, e.g. "minWidthExtended.DisplayPropertyFieldInBox();" becomes "EditorGUILayout.PropertyField(minWidthExtended);". Also remove the reference to the interface "IRectTransformGetable".

@QuantumCalzone
Copy link
Author

This stuff is golden, ought to be built into unity. For those who use this, the "DisplayPropertyFieldInBox()" methods seem to be missing, just replace with standard unity ui logic, e.g. "minWidthExtended.DisplayPropertyFieldInBox();" becomes "EditorGUILayout.PropertyField(minWidthExtended);". Also remove the reference to the interface "IRectTransformGetable".

Thanks for your feedback! I cleaned up those old references I forgot to remove before.

@mobyjames
Copy link

This is amazing. Exactly what I needed.

@aaronerod
Copy link

Hey, thanks for this!
I have a question. Do I have to do something special to use MaxHeight?
It isn't working for me.

@QuantumCalzone
Copy link
Author

Hey, thanks for this!
I have a question. Do I have to do something special to use MaxHeight?
It isn't working for me.

Is Flexible Height enabled and/or is Preferred Height enabled and its resulting value at something greater than the Max Height?

@QuantumCalzone
Copy link
Author

Also, feel free to use the package version of this for easier installation. You can find it here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment