Skip to content

Instantly share code, notes, and snippets.

@SolarianZ
Last active April 26, 2024 11:33
Show Gist options
  • Save SolarianZ/d7572ff6047dccabe58f861022fb0b53 to your computer and use it in GitHub Desktop.
Save SolarianZ/d7572ff6047dccabe58f861022fb0b53 to your computer and use it in GitHub Desktop.
{"category": "Unity Engine/Editor/Extensions", "keywords": "Unity, Editor, UI, Odin, Foldout, Collapse, List, Element"} Odin extenssion for foldout elements in list.
// Odin extension for foldout elements in list.
// Example:
// [Serializable]
// public class MyData1 : IFoldoutableInList
// {
// // members...
// }
// [Serializable]
// public class MyData2 : IForceFoldoutableInList
// {
// // members...
// }
// public class Test : MonoBehaviour
// {
// [ElementFoldoutable]
// public List<MyData1> dataList1 = new List<MyData1>();
// public List<MyData2> dataList2 = new List<MyData2>();
// }
using System;
using System.Collections;
using System.Diagnostics;
using Sirenix.OdinInspector.Editor;
using UnityEditor;
using UnityEngine;
// Put the following classes to the runtime folder
public interface IFoldoutableInList { } // Work with ElementFoldoutableAttribute
public interface IForceFoldoutableInList : IFoldoutableInList { } // No need to use ElementFoldoutableAttribute
[Conditional("UNITY_EDITOR")]
public class ElementFoldoutableAttribute : Attribute { } // Work with IFoldoutableInList
// Put the following class to the editor folder
public class FoldoutableListElementDrawer : OdinValueDrawer<IFoldoutableInList> // use OdinValueDrawer<object> for all types
{
protected override void DrawPropertyLayout(GUIContent label)
{
if (!(Property.Parent.ValueEntry.WeakSmartValue is IList))
{
CallNextDrawer(label);
return;
}
string propertyLabel = null;
foreach (InspectorProperty child in Property.Children)
{
if (child.Info.TypeOfValue == typeof(string))
{
string childValue = child.ValueEntry.WeakSmartValue?.ToString();
if (!string.IsNullOrEmpty(childValue))
{
propertyLabel = childValue;
}
break;
}
}
propertyLabel ??= $"Element {Property.Index}";
Property.State.Expanded = EditorGUILayout.Foldout(Property.State.Expanded, propertyLabel);
if (!Property.State.Expanded)
{
return;
}
using (new EditorGUI.IndentLevelScope())
{
CallNextDrawer(label);
}
}
protected override bool CanDrawValueProperty(InspectorProperty property)
{
if (typeof(IForceFoldoutableInList).IsAssignableFrom(property.Info.TypeOfValue))
{
return true && base.CanDrawValueProperty(property);
}
foreach (Attribute attribute in property.Attributes)
{
if (attribute is ElementFoldoutableAttribute)
{
return true && base.CanDrawValueProperty(property);
}
}
return false;
}
}
@SolarianZ
Copy link
Author

There is a simpler way to achieve foldoutable list elements:

  • Add Sirenix.OdinInspector.ListDrawerSettingsAttribute to the list and assign values to the ShowIndexLabel and ListElementLabelName parameters.
  • Make sure there is a field or property in the type of the list element with a name matching the value assigned to the ListElementLabelName parameter (in this example, the name is "_comment").
    ZQYCR6L%{(S917D(NX RGPC

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