2024-07-15 Unity插件 Odin Inspector4 —— Collection Attributes

1 说明

​ 本文介绍 Odin Inspector 插件中集合(Dictionary、List)相关特性的使用方法。

2 集合相关特性

2.1 DictionaryDrawerSettings

自定义 Dictionary 在 Inspector 窗口中的显示样式。类需要继承 SerializedMonoBehaviour。

  • string KeyLabel = "Key"

    显示的键标题名。

  • ValueLabel = "Value"

    显示的值标题名。

  • DictionaryDisplayOptions DisplayMode

    字典显示样式。

  • bool IsReadOnly = false

    键是否只读(不是值)。

image-20240715012958264
// DictionaryExamplesComponent.cs

using Sirenix.OdinInspector;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class DictionaryExamplesComponent : SerializedMonoBehaviour
{
    [InfoBox("In order to serialize dictionaries, all we need to do is to inherit our class from SerializedMonoBehaviour.")]
    public Dictionary<int, Material> IntMaterialLookup;

    [DictionaryDrawerSettings(IsReadOnly = true)]
    public Dictionary<string, string> StringStringDictionary;

    [DictionaryDrawerSettings(KeyLabel = "Custom Key Name", ValueLabel = "Custom Value Label")]
    public Dictionary<SomeEnum, MyCustomType> CustomLabels = new Dictionary<SomeEnum, MyCustomType>() {
        { SomeEnum.First, new MyCustomType() },
        { SomeEnum.Second, new MyCustomType() },
    };

    [DictionaryDrawerSettings(DisplayMode = DictionaryDisplayOptions.ExpandedFoldout)]
    public Dictionary<string, List<int>> StringListDictionary = new Dictionary<string, List<int>>() {
        { "Numbers", new List<int>() { 1, 2, 3, 4, } },
    };

    [DictionaryDrawerSettings(DisplayMode = DictionaryDisplayOptions.Foldout)]
    public Dictionary<SomeEnum, MyCustomType> EnumObjectLookup = new Dictionary<SomeEnum, MyCustomType>() {
        { SomeEnum.Third, new MyCustomType() },
        { SomeEnum.Fourth, new MyCustomType() },
    };

    [InlineProperty(LabelWidth = 90)]
    public struct MyCustomType
    {
        public int        SomeMember;
        public GameObject SomePrefab;
    }

    public enum SomeEnum
    {
        First, Second, Third, Fourth, AndSoOn
    }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData() {
        IntMaterialLookup = new Dictionary<int, Material>() {
            { 1, ExampleHelper.GetMaterial() },
            { 7, ExampleHelper.GetMaterial() },
        };

        StringStringDictionary = new Dictionary<string, string>() {
            { "One", ExampleHelper.GetString() },
            { "Seven", ExampleHelper.GetString() },
        };
    }
#endif
}

2.2 ListDrawerSettings

自定义 List 在 Inspector 窗口中的显示样式。

  • bool IsReadOnly = true

    是否在 Inspector 窗口中只读。

  • int NumberOfItemsPerPage

    列表每页的成员个数,超过该个数则会翻页。

  • bool ShowIndexLabels

    是否显示列表每个 item 的下标。

  • string ListElementLabelName

    指定每个列表元素内的成员名称。

  • bool DraggableItems

    列表成员是否可以在 Inspector 窗口中通过拖拽改变顺序。

  • bool ShowFoldout = true

    列表成员是否折叠显示。

  • bool ShowPaging = true

    是否启用分页显示。

  • bool ShowItemCount = true

    是否显示成员个数。

  • string OnBeginListElementGUI

    在每个列表元素之前调用的方法。引用的成员必须具有对应名称的方法。返回类型为 void,参数为 int 类型,表示该成员在列表中的索引。

  • string OnEndListElementGUI

    在每个列表元素之后调用的方法。引用的成员必须具有对应名称的方法。返回类型为 void,参数为 int 类型,表示该成员在列表中的索引。

  • string OnTitleBarGUI

    使用此功能将自定义 GUI 注入列表的标题栏。

  • string CustomAddFunction

    覆盖向列表中添加对象的默认行为。

    如果引用的方法返回列表类型元素,则每个选定对象将调用一次。

    如果引用的方法返回 void,则无论选择了多少对象,都只会被调用一次。

image-20240715020016676
// ListExamplesComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.Utilities.Editor;
#endif

public class ListExamplesComponent : MonoBehaviour
{
#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [PropertyOrder(int.MinValue), OnInspectorGUI]
    private void DrawIntroInfoBox() {
        // SirenixEditorGUI.InfoMessageBox("Out of the box, Odin significantly upgrades the drawing of lists and arrays in the inspector - across the board, without you ever lifting a finger.");
    }
#endif

    [Title("List Basics")]
    // [InfoBox("List elements can now be dragged around to reorder them and deleted individually, and lists have paging (try adding a lot of elements!). You can still drag many assets at once into lists from the project view - just drag them into the list itself and insert them where you want to add them.")]
    public List<float> FloatList;

    // [InfoBox("Applying a [Range] attribute to this list instead applies it to all of its float entries.")]
    [Range(0, 1)]
    public float[] FloatRangeArray;

    // [InfoBox("Lists can be made read-only in different ways.")]
    [ListDrawerSettings(IsReadOnly = true)]
    public int[] ReadOnlyArray1 = new int[] { 1, 2, 3 };

    [ReadOnly]
    public int[] ReadOnlyArray2 = new int[] { 1, 2, 3 };

    public SomeOtherStruct[] SomeStructList;

    [Title("Advanced List Customization")]
    // [InfoBox("Using [ListDrawerSettings], lists can be customized in a wide variety of ways.")]
    [ListDrawerSettings(NumberOfItemsPerPage = 5)]
    public int[] FiveItemsPerPage;

    [ListDrawerSettings(ShowIndexLabels = true, ListElementLabelName = "SomeString")]
    public SomeStruct[] IndexLabels;

    [ListDrawerSettings(DraggableItems = false, ShowFoldout = false, ShowIndexLabels = true, ShowPaging = false, ShowItemCount = false,
                        HideRemoveButton = true)]
    public int[] MoreListSettings = new int[] { 1, 2, 3 };

    [ListDrawerSettings(OnBeginListElementGUI = "BeginDrawListElement", OnEndListElementGUI = "EndDrawListElement")]
    public SomeStruct[] InjectListElementGUI;

    [ListDrawerSettings(OnTitleBarGUI = "DrawRefreshButton")]
    public List<int> CustomButtons;

    [ListDrawerSettings(CustomAddFunction = "CustomAddFunction")]
    public List<int> CustomAddBehaviour;

    [Serializable]
    public struct SomeStruct
    {
        public string SomeString;
        public int    One;
        public int    Two;
        public int    Three;
    }

    [Serializable]
    public struct SomeOtherStruct
    {
        [HorizontalGroup("Split", 55), PropertyOrder(-1)]
        [PreviewField(50, Sirenix.OdinInspector.ObjectFieldAlignment.Left), HideLabel]
        public UnityEngine.MonoBehaviour SomeObject;

        [FoldoutGroup("Split/$Name", false)]
        public int A, B, C;

        [FoldoutGroup("Split/$Name", false)]
        public int Two;

        [FoldoutGroup("Split/$Name", false)]
        public int Three;

        private string Name { get { return this.SomeObject ? this.SomeObject.name : "Null"; } }
    }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private void BeginDrawListElement(int index) {
        SirenixEditorGUI.BeginBox(this.InjectListElementGUI[index].SomeString);
    }

    private void EndDrawListElement(int index) {
        SirenixEditorGUI.EndBox();
    }

    private void DrawRefreshButton() {
        if (SirenixEditorGUI.ToolbarButton(EditorIcons.Refresh)) {
            Debug.Log(this.CustomButtons.Count.ToString());
        }
    }

    private int CustomAddFunction() {
        Debug.Log("Custom add function called!");
        return this.CustomAddBehaviour.Count;
    }
#endif
}

2.3 TableColumnWidth

控制 List 成员显示在表格中显示的宽度。

  • int width

    宽度。

  • bool resizable = true

    宽度是否可通过拖拽调节。

image-20240715021137994
// TableColumnWidthExampleComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class TableColumnWidthExampleComponent : MonoBehaviour
{
    [TableList(ShowIndexLabels = true)]
    public List<MyItem> List = new List<MyItem>() {
        new MyItem(),
        new MyItem(),
        new MyItem(),
    };

    [Serializable]
    public class MyItem
    {
        [PreviewField(Height = 20)]
        [TableColumnWidth(30, Resizable = false)]
        public Texture2D Icon;

        [TableColumnWidth(60)]
        public int ID;

        public string Name;

#if UNITY_EDITOR // Editor-related code must be excluded from builds
        [OnInspectorInit]
        private void CreateData() { // 每次点击 Inspector 窗口时,更新 Texture
            Icon = ExampleHelper.GetTexture();
        }
#endif
    }
}

2.4 TableList

将 List 绘制成表格形状。

  • bool IsReadOnly = true

    是否在 Inspector 窗口中只读。

  • int NumberOfItemsPerPage

    列表每页的成员个数,超过该个数则会翻页。

  • bool ShowIndexLabels

    是否显示列表每个 item 的下标。

  • bool ShowPaging = true

    是否启用分页显示。

  • bool ShowItemCount = true

    是否显示成员个数。

  • bool HideToolbar = false

    是否隐藏标题栏。

  • bool DrawScrollView = true

    是否绘制滚动条。

  • int MaxScrollViewHeight/MinScrollViewHeight

    滚动条绘制的范围(最大高度/最小高度),单位:像素。

  • bool AlwaysExpanded

    List 是否可折叠。

image-20240715021626235
// TableListExamplesComponent.cs

using Sirenix.OdinInspector;
using System;
using System.Collections.Generic;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class TableListExamplesComponent : MonoBehaviour
{
    [TableList(ShowIndexLabels = true)]
    public List<SomeCustomClass> TableListWithIndexLabels = new List<SomeCustomClass>() {
        new SomeCustomClass(),
        new SomeCustomClass(),
    };

    [TableList(DrawScrollView = true, MaxScrollViewHeight = 200, MinScrollViewHeight = 100)]
    public List<SomeCustomClass> MinMaxScrollViewTable = new List<SomeCustomClass>() {
        new SomeCustomClass(),
        new SomeCustomClass(),
    };

    [TableList(AlwaysExpanded = true, DrawScrollView = false)]
    public List<SomeCustomClass> AlwaysExpandedTable = new List<SomeCustomClass>() {
        new SomeCustomClass(),
        new SomeCustomClass(),
    };

    [TableList(ShowPaging = true, NumberOfItemsPerPage = 3)]
    public List<SomeCustomClass> TableWithPaging = new List<SomeCustomClass>() {
        new SomeCustomClass(),
        new SomeCustomClass(),
    };

    [Serializable]
    public class SomeCustomClass
    {
        [TableColumnWidth(57, Resizable = false)]
        [PreviewField(Alignment = ObjectFieldAlignment.Center)]
        public Texture Icon;

        [TextArea]
        public string Description;

        [VerticalGroup("Combined Column"), LabelWidth(22)]
        public string A, B, C;

        [TableColumnWidth(60)]
        [Button, VerticalGroup("Actions")]
        public void Test1() { }

        [TableColumnWidth(60)]
        [Button, VerticalGroup("Actions")]
        public void Test2() { }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
        [OnInspectorInit]
        private void CreateData() {
            Description = ExampleHelper.GetString();
            Icon        = ExampleHelper.GetTexture();
        }
#endif
    }
}

2.5 TableMatrix

绘制二维数组。

  1. 单元格绘制。

    • string HorizontalTitle

      水平标题。

    • bool SquareCells

      如果为 true,则每行的高度将与第一个单元格的宽度相同。

image-20240715022259336
// TableMatrixExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

#if UNITY_EDITOR // Editor namespaces can only be used in the editor.
using Sirenix.OdinInspector.Editor.Examples;
#endif

public class TableMatrixExamplesComponent : SerializedMonoBehaviour
{
    [TableMatrix(HorizontalTitle = "Square Celled Matrix", SquareCells = true)]
    public Texture2D[,] SquareCelledMatrix;

    [TableMatrix(SquareCells = true)]
    public Mesh[,] PrefabMatrix;

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData() {
        SquareCelledMatrix = new Texture2D[8, 4] {
            { ExampleHelper.GetTexture(), null, null, null },
            { null, ExampleHelper.GetTexture(), null, null },
            { null, null, ExampleHelper.GetTexture(), null },
            { null, null, null, ExampleHelper.GetTexture() },
            { ExampleHelper.GetTexture(), null, null, null },
            { null, ExampleHelper.GetTexture(), null, null },
            { null, null, ExampleHelper.GetTexture(), null },
            { null, null, null, ExampleHelper.GetTexture() },
        };

        PrefabMatrix = new Mesh[8, 4] {
            { ExampleHelper.GetMesh(), null, null, null },
            { null, ExampleHelper.GetMesh(), null, null },
            { null, null, ExampleHelper.GetMesh(), null },
            { null, null, null, ExampleHelper.GetMesh() },
            { null, null, null, ExampleHelper.GetMesh() },
            { null, null, ExampleHelper.GetMesh(), null },
            { null, ExampleHelper.GetMesh(), null, null },
            { ExampleHelper.GetMesh(), null, null, null },
        };
    }
#endif
}
  1. 表格绘制

    • bool IsReadOnly

      如果为 true,则插入、删除和拖动列和行将不可用。但单元格本身仍将是可修改的。

      如果要禁用所有内容,可以使用 ReadOnly 属性。

    • string VerticalTitle

      垂直标题。

image-20240715022550956
// TableMatrixTitleExampleComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class TableMatrixTitleExampleComponent : SerializedMonoBehaviour
{
    [TableMatrix(HorizontalTitle = "Read Only Matrix", IsReadOnly = true)]
    public int[,] ReadOnlyMatrix = new int[5, 5];

    [TableMatrix(HorizontalTitle = "X axis", VerticalTitle = "Y axis")]
    public InfoMessageType[,] LabledMatrix = new InfoMessageType[6, 6];
}
  1. 图形绘制

    • string DrawElementMethod

      覆盖绘制每个单元格的方式。

      输入参数:Rect rect, T value

      输出:T

    • bool ResizableColumns = true

      列是否可调整大小。

    • RowHeight

      行高,0 表示默认高度。

    • bool Transpose

      如果为 true,则表的行/列颠倒绘制(C# 初始化顺序)。

image-20240715023026208
// TransposeTableMatrixExampleComponent.cs

using Sirenix.OdinInspector;
using Sirenix.Utilities;
using UnityEngine;

public class TransposeTableMatrixExampleComponent : SerializedMonoBehaviour
{
    [TableMatrix(HorizontalTitle = "Custom Cell Drawing", DrawElementMethod = nameof(DrawColoredEnumElement), ResizableColumns = false, RowHeight = 16)]
    public bool[,] CustomCellDrawing;

    [ShowInInspector, DoNotDrawAsReference]
    [TableMatrix(HorizontalTitle = "Transposed Custom Cell Drawing", DrawElementMethod = "DrawColoredEnumElement", ResizableColumns = false, RowHeight = 16, Transpose = true)]
    public bool[,] Transposed { get { return CustomCellDrawing; } set { CustomCellDrawing = value; } }

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    private static bool DrawColoredEnumElement(Rect rect, bool value) {
        if (Event.current.type == EventType.MouseDown && rect.Contains(Event.current.mousePosition)) {
            value       = !value;
            GUI.changed = true;
            Event.current.Use();
        }

        UnityEditor.EditorGUI.DrawRect(rect.Padding(1), value ? new Color(0.1f, 0.8f, 0.2f) : new Color(0, 0, 0, 0.5f));

        return value;
    }

    [OnInspectorInit]
    private void CreateData() {
        // =)
        this.CustomCellDrawing        = new bool[15, 15];
        this.CustomCellDrawing[6, 5]  = true;
        this.CustomCellDrawing[6, 6]  = true;
        this.CustomCellDrawing[6, 7]  = true;
        this.CustomCellDrawing[8, 5]  = true;
        this.CustomCellDrawing[8, 6]  = true;
        this.CustomCellDrawing[8, 7]  = true;
        this.CustomCellDrawing[5, 9]  = true;
        this.CustomCellDrawing[5, 10] = true;
        this.CustomCellDrawing[9, 9]  = true;
        this.CustomCellDrawing[9, 10] = true;
        this.CustomCellDrawing[6, 11] = true;
        this.CustomCellDrawing[7, 11] = true;
        this.CustomCellDrawing[8, 11] = true;
    }
#endif
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔗理苦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值