文章目录
- 1 说明
- 2 集合相关特性
- 2.1 DictionaryDrawerSettings
- 2.2 ListDrawerSettings
- 2.3 TableColumnWidth
- 2.4 TableList
- 2.5 TableMatrix
1 说明
本文介绍 Odin Inspector 插件中集合(Dictionary、List)相关特性的使用方法。
2 集合相关特性
2.1 DictionaryDrawerSettings
自定义 Dictionary 在 Inspector 窗口中的显示样式。类需要继承 SerializedMonoBehaviour。
string KeyLabel = "Key"
显示的键标题名。
ValueLabel = "Value"
显示的值标题名。
DictionaryDisplayOptions DisplayMode
字典显示样式。
bool IsReadOnly = false
键是否只读(不是值)。
// 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,则无论选择了多少对象,都只会被调用一次。
// 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
宽度是否可通过拖拽调节。
// 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 是否可折叠。
// 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
绘制二维数组。
-
单元格绘制。
-
string HorizontalTitle
水平标题。
-
bool SquareCells
如果为 true,则每行的高度将与第一个单元格的宽度相同。
-
// 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
}
-
表格绘制
-
bool IsReadOnly
如果为 true,则插入、删除和拖动列和行将不可用。但单元格本身仍将是可修改的。
如果要禁用所有内容,可以使用 ReadOnly 属性。
-
string VerticalTitle
垂直标题。
-
// 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];
}
-
图形绘制
-
string DrawElementMethod
覆盖绘制每个单元格的方式。
输入参数:
Rect rect, T value
输出:
T
-
bool ResizableColumns = true
列是否可调整大小。
-
RowHeight
行高,0 表示默认高度。
-
bool Transpose
如果为 true,则表的行/列颠倒绘制(C# 初始化顺序)。
-
// 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
}