2024-07-18 Unity插件 Odin Inspector8 —— Type Specific Attributes

news2024/9/21 21:52:42

文章目录

  • 1 说明
  • 2 特定类型特性
    • 2.1 AssetList
    • 2.2 AssetSelector
    • 2.3 ChildGameObjectsOnly
    • 2.4 ColorPalette
    • 2.5 DisplayAsString
    • 2.6 EnumPaging
    • 2.7 EnumToggleButtons
    • 2.8 FilePath
    • 2.9 FolderPath
    • 2.10 HideInInlineEditors
    • 2.11 HideInTables
    • 2.12 HideMonoScript
    • 2.13 HideReferenceObjectPicker
    • 2.14 InlineEditor
    • 2.15 Multiline
    • 2.16 PreviewField
    • 2.17 PolymorphicDrawerSettings
    • 2.18 TypeDrawerSettings
    • 2.19 SceneObjectsOnly
    • 2.20 TableList
    • 2.21 TableMatrix
    • 2.22 Toggle
    • 2.23 ToggleGroup

1 说明

​ 本文介绍 Odin Inspector 插件中有关特定类型特性的使用方法。

2 特定类型特性

2.1 AssetList

用于 List、Array 和单个对象,将默认导航选择窗口替换为可筛选的 Asset 列表,以筛选、包含或排除 List、Array 中的 Asset。

  • string Path

    筛选 Asset 列表,仅包括位于指定路径的 Asset。

  • bool AutoPopulate

    如果为 true ,则将 Asset 列表中找到并显示的所有资产自动添加到列表中。

  • string LayerNames

    筛选 Asset 列表,使其仅包含具有指定 Layer 的资源。

  • string AssetNamePrefix

    筛选 Asset 列表,使其仅包含名称以开头的 Asset。

  • string Tags

    标签列表(以逗号分隔),用于筛选 Asset 列表。

  • string CustomFilterMethod

    筛选 Asset 列表,使其仅包含给定筛选方法返回 true 的 Asset。

image-20240718015148658
// AssetListExamplesComponent.cs

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

public class AssetListExamplesComponent : MonoBehaviour
{
    [AssetList]
    [PreviewField(70, ObjectFieldAlignment.Center)]
    public Texture2D SingleObject;

    [AssetList(Path = "/Plugins/Sirenix/")]
    public List<ScriptableObject> AssetList;

    [FoldoutGroup("Filtered Odin ScriptableObjects", expanded: false)]
    [AssetList(Path = "Plugins/Sirenix/")]
    public ScriptableObject Object;

    [AssetList(AutoPopulate = true, Path = "Plugins/Sirenix/")]
    [FoldoutGroup("Filtered Odin ScriptableObjects", expanded: false)]
    public List<ScriptableObject> AutoPopulatedWhenInspected;

    [AssetList(LayerNames = "MyLayerName")]
    [FoldoutGroup("Filtered AssetLists examples")]
    public GameObject[] AllPrefabsWithLayerName;

    [AssetList(AssetNamePrefix = "Rock")]
    [FoldoutGroup("Filtered AssetLists examples")]
    public List<GameObject> PrefabsStartingWithRock;

    [FoldoutGroup("Filtered AssetLists examples")]
    [AssetList(Tags = "MyTagA, MyTabB", Path = "/Plugins/Sirenix/")]
    public List<GameObject> GameObjectsWithTag;

    [FoldoutGroup("Filtered AssetLists examples")]
    [AssetList(CustomFilterMethod = "HasRigidbodyComponent")]
    public List<GameObject> MyRigidbodyPrefabs;

    private bool HasRigidbodyComponent(GameObject obj) {
        return obj.GetComponent<Rigidbody>() != null;
    }
}

2.2 AssetSelector

可用于所有 Unity 类型,在对象字段旁边添加小按钮。单击该按钮将显示资产下拉列表以供选择,可从该属性中进行自定义。

  • bool FlattenTreeView

    下拉列表是否树状显示。

  • string Paths

    指定搜索的文件夹。不指定任何文件夹则在整个项目中搜索(使用“|”作为分隔符表示多条路径)。

  • string Filter

    调用 AssetDatabase.FindAssets 时使用的过滤器。

  • bool DisableListAddButtonBehaviour = false

    禁用列表添加按钮行为。

  • bool DrawDropdownForListElements = true

    当 ValueDropdown 特性应用于该对象时,则禁用 DrawDropdownForListElements 将正常呈现所有子元素。

  • bool ExcludeExistingValuesInList

    当 ValueDropdown 特性应用于该对象时,并且 IsUniqueList 为 true,则启用 ExcludeExistingValuesInList 时,排除现有值,而不是显示一个复选框,指示该项是否已包含在内。

  • bool IsUniqueList = true

    子元素是否唯一。

  • bool ExpandAllMenuItems = true

    如果下拉菜单呈现树视图,则将其设置为 true 时,默认情况下所有内容都会被展开显示。

  • string DropdownTitle

    自定义下拉列表标题。

image-20240718020158603
// AssetSelectorExamplesComponent.cs

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

public class AssetSelectorExamplesComponent : MonoBehaviour
{
    [AssetSelector]
    public Material AnyAllMaterials;

    [AssetSelector]
    public Material[] ListOfAllMaterials;

    [AssetSelector(FlattenTreeView = true)]
    public Material NoTreeView;

    [AssetSelector(Paths = "Assets/MyScriptableObjects")]
    public ScriptableObject ScriptableObjectsFromFolder;

    [AssetSelector(Paths = "Assets/MyScriptableObjects|Assets/Other/MyScriptableObjects")]
    public Material ScriptableObjectsFromMultipleFolders;

    [AssetSelector(Filter = "name t:type l:label")]
    public UnityEngine.Object AssetDatabaseSearchFilters;

    [Title("Other Minor Features")]
    [AssetSelector(DisableListAddButtonBehaviour = true)]
    public List<GameObject> DisableListAddButtonBehaviour;

    [AssetSelector(DrawDropdownForListElements = false)]
    public List<GameObject> DisableListElementBehaviour;

    [AssetSelector(ExcludeExistingValuesInList = false)]
    public List<GameObject> ExcludeExistingValuesInList;

    [AssetSelector(IsUniqueList = false)]
    public List<GameObject> DisableUniqueListBehaviour;

    [AssetSelector(ExpandAllMenuItems = true)]
    public List<GameObject> ExpandAllMenuItems;

    [AssetSelector(DropdownTitle = "Custom Dropdown Title")]
    public List<GameObject> CustomDropdownTitle;
}

2.3 ChildGameObjectsOnly

可用于 Components 和 GameObject,并在对象旁添加小按钮,点击按钮将显示其子物体中所有满足条件的对象。

  • IncludeSelf = true

    是否包含自身。

  • bool IncludeInactive

    是否包含未激活的子物体。

image-20240718021903335
// ChildGameObjectsOnlyAttributeExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class ChildGameObjectsOnlyAttributeExamplesComponent : MonoBehaviour
{
    [ChildGameObjectsOnly]
    public Transform ChildOrSelfTransform;

    [ChildGameObjectsOnly]
    public GameObject ChildGameObject;

    [ChildGameObjectsOnly(IncludeSelf = false)]
    public Light[] Lights;
}

2.4 ColorPalette

用于任何 Color,允许从一组预定义的颜色选项中进行选择。

  • string paletteName

    调色板名称。

  • bool ShowAlpha = true

    是否显示透明度。

image-20240718022418293
// ColorPaletteExamplesComponent.cs

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

public class ColorPaletteExamplesComponent : MonoBehaviour
{
    [ColorPalette]
    public Color ColorOptions;

    [ColorPalette("Underwater")]
    public Color UnderwaterColor;

    [ColorPalette("My Palette")]
    public Color MyColor;

    public string DynamicPaletteName = "Clovers";

    // The ColorPalette attribute supports both 
    // member references and attribute expressions.
    [ColorPalette("$DynamicPaletteName")]
    public Color DynamicPaletteColor;

    [ColorPalette("Fall"), HideLabel]
    public Color WideColorPalette;

    [ColorPalette("Clovers")]
    public Color[] ColorArray;

    // ------------------------------------
    // Color palettes can be accessed and modified from code.
    // Note that the color palettes will NOT automatically be included in your builds.
    // But you can easily fetch all color palettes via the ColorPaletteManager 
    // and include them in your game like so:
    // ------------------------------------

    [FoldoutGroup("Color Palettes", expanded: false)]
    [ListDrawerSettings(IsReadOnly = true)]
    [PropertyOrder(9)]
    public List<ColorPalette> ColorPalettes;

    [Serializable]
    public class ColorPalette
    {
        [HideInInspector]
        public string Name;

        [LabelText("$Name")]
        [ListDrawerSettings(IsReadOnly = true, ShowFoldout = false)]
        public Color[] Colors;
    }

#if UNITY_EDITOR
    [FoldoutGroup("Color Palettes"), Button(ButtonSizes.Large), GUIColor(0, 1, 0), PropertyOrder(8)]
    private void FetchColorPalettes() {
        this.ColorPalettes = Sirenix.OdinInspector.Editor.ColorPaletteManager.Instance.ColorPalettes
                                    .Select(x => new ColorPalette() {
                                         Name   = x.Name,
                                         Colors = x.Colors.ToArray()
                                     })
                                    .ToList();
    }
#endif
}

2.5 DisplayAsString

用于任何对象,在 Inpector 窗口中将对象显示为字符串文本。想在 Inpector 窗口中显示字符串,但不允许进行任何编辑时,请使用此选项。

  • bool overflow

    true:字符串将溢出绘制的空间,并在没有足够的空间容纳文本时被剪切。

    false:如果绘制时没有足够的空间,字符串将扩展为多行。

  • int fontSize

    字体大小。

  • TextAlignment alignment

    对齐方式。

  • bool enableRichText

    是否开启富文本。

  • string Format

    用于格式化值的字符串。类型必须实现 IFormattable 接口。

image-20240718022535984
// DisplayAsStringExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class DisplayAsStringExamplesComponent : MonoBehaviour
{
    [InfoBox(
                "Instead of disabling values in the inspector in order to show some information or debug a value. " +
                "You can use DisplayAsString to show the value as text, instead of showing it in a disabled drawer")]
    [DisplayAsString]
    public Color SomeColor;

    [BoxGroup("SomeBox")]
    [HideLabel]
    [DisplayAsString]
    public string SomeText = "Lorem Ipsum";

    [InfoBox("The DisplayAsString attribute can also be configured to enable or disable overflowing to multiple lines.")]
    [HideLabel]
    [DisplayAsString]
    public string Overflow = "A very very very very very very very very very long string that has been configured to overflow.";

    [HideLabel]
    [DisplayAsString(false)]
    public string DisplayAllOfIt = "A very very very very very very very very long string that has been configured to not overflow.";

    [InfoBox("Additionally, you can also configure the string's alignment, font size, and whether it should support rich text or not.")]
    [DisplayAsString(false, 20, TextAlignment.Center, true)]
    public string CustomFontSizeAlignmentAndRichText = "This string is <b><color=#FF5555><i>super</i> <size=24>big</size></color></b> and centered.";
}

2.6 EnumPaging

为枚举添加“下一步”和“上一步”按钮选择器,循环查看枚举属性的可用值。

image-20240715003928053
// EnumPagingExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class EnumPagingExamplesComponent : MonoBehaviour
{
    [EnumPaging]
    public SomeEnum SomeEnumField;

    public enum SomeEnum
    {
        A, B, C
    }

#if UNITY_EDITOR // UnityEditor.Tool is an editor-only type, so this example will not work in a build
    [EnumPaging, OnValueChanged("SetCurrentTool")]
    [InfoBox("Changing this property will change the current selected tool in the Unity editor.")]
    public UnityEditor.Tool sceneTool;

    private void SetCurrentTool() {
        UnityEditor.Tools.current = this.sceneTool;
    }
#endif
}

2.7 EnumToggleButtons

在水平按钮组中绘制枚举,而不是下拉列表。

image-20240715004031983
// EnumToggleButtonsExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class EnumToggleButtonsExamplesComponent : MonoBehaviour
{
    [Title("Default")]
    public SomeBitmaskEnum DefaultEnumBitmask;

    [Title("Standard Enum")]
    [EnumToggleButtons]
    public SomeEnum SomeEnumField; // 单选枚举

    [EnumToggleButtons, HideLabel]
    public SomeEnum WideEnumField; // 单选枚举

    [Title("Bitmask Enum")]
    [EnumToggleButtons]
    public SomeBitmaskEnum BitmaskEnumField; // 多选枚举

    [EnumToggleButtons, HideLabel]
    public SomeBitmaskEnum EnumFieldWide; // 多选枚举

    [Title("Icon Enum")]
    [EnumToggleButtons, HideLabel]
    public SomeEnumWithIcons EnumWithIcons;

    [EnumToggleButtons, HideLabel]
    public SomeEnumWithIconsAndNames EnumWithIconsAndNames;

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

    public enum SomeEnumWithIcons
    {
        [LabelText(SdfIconType.TextLeft)]   TextLeft,
        [LabelText(SdfIconType.TextCenter)] TextCenter,
        [LabelText(SdfIconType.TextRight)]  TextRight,
    }

    public enum SomeEnumWithIconsAndNames
    {
        [LabelText("Align Left", SdfIconType.TextLeft)]
        TextLeft,

        [LabelText("Align Center", SdfIconType.TextCenter)]
        TextCenter,

        [LabelText("Align Right", SdfIconType.TextRight)]
        TextRight,
    }

    [System.Flags]
    public enum SomeBitmaskEnum
    {
        A   = 1 << 1,
        B   = 1 << 2,
        C   = 1 << 3,
        All = A | B | C
    }
}

2.8 FilePath

用于字符串,为文件路径提供接口。支持下拉选择文件路径和拖拽文件路径。

  • string ParentFolder

    父路径。可以相对于 Unity 项目,也可以是绝对路径。

  • string Extensions

    文件扩展名列表(以逗号分隔)。扩展名中的 “.” 可不写。

  • bool AbsolutePath

    是否为绝对路径。

  • bool RequireExistingPath

    true:若路径不存在,则显示警告提示。

  • bool UseBackslashes

    是否使用反斜杠(默认使用斜杠)。

image-20240718024034855
// FilePathExamplesComponent.cs
using Sirenix.OdinInspector;
using UnityEngine;

public class FilePathExamplesComponent : MonoBehaviour
{
    // By default, FolderPath provides a path relative to the Unity project.
    [FilePath]
    public string UnityProjectPath;
    
    // It is possible to provide custom parent path. Parent paths can be relative to the Unity project, or absolute.
    [FilePath(ParentFolder = "Assets/Plugins/Sirenix")]
    public string RelativeToParentPath;
    
    // Using parent path, FilePath can also provide a path relative to a resources folder.
    [FilePath(ParentFolder = "Assets/Resources")]
    public string ResourcePath;
    
    // Provide a comma seperated list of allowed extensions. Dots are optional.
    [FilePath(Extensions = "cs")]
    [BoxGroup("Conditions")]
    public string ScriptFiles;
    
    // By setting AbsolutePath to true, the FilePath will provide an absolute path instead.
    [FilePath(AbsolutePath = true)]
    [BoxGroup("Conditions")]
    public string AbsolutePath;
    
    // FilePath can also be configured to show an error, if the provided path is invalid.
    [FilePath(RequireExistingPath = true)]
    [BoxGroup("Conditions")]
    public string ExistingPath;
    
    // By default, FilePath will enforce the use of forward slashes. It can also be configured to use backslashes instead.
    [FilePath(UseBackslashes = true)]
    [BoxGroup("Conditions")]
    public string Backslashes;
    
    // FilePath also supports member references with the $ symbol.
    [FilePath(ParentFolder = "$DynamicParent", Extensions = "$DynamicExtensions")]
    [BoxGroup("Member referencing")]
    public string DynamicFilePath;
    
    [BoxGroup("Member referencing")]
    public string DynamicParent = "Assets/Plugins/Sirenix";
    
    [BoxGroup("Member referencing")]
    public string DynamicExtensions = "cs, unity, jpg";
    
    // FilePath also supports lists and arrays.
    [FilePath(ParentFolder = "Assets/Plugins/Sirenix/Demos/Odin Inspector")]
    [BoxGroup("Lists")]
    public string[] ListOfFiles;
}

2.9 FolderPath

用于字符串,为目录路径提供接口。支持下拉选择文件夹目录和拖拽文件夹目录。

  • string ParentFolder

    父路径。可以相对于 Unity 项目,也可以是绝对路径。

  • bool AbsolutePath

    是否为绝对路径。

  • bool RequireExistingPath

    true:若路径不存在,则显示警告提示。

  • bool UseBackslashes

    是否使用反斜杠(默认使用斜杠)。

image-20240718024439650
// FolderPathExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class FolderPathExamplesComponent : MonoBehaviour
{
    // By default, FolderPath provides a path relative to the Unity project.
    [FolderPath]
    public string UnityProjectPath;

    // It is possible to provide custom parent path. Parent paths can be relative to the Unity project, or absolute.
    [FolderPath(ParentFolder = "Assets/Plugins/Sirenix")]
    public string RelativeToParentPath;

    // Using parent path, FolderPath can also provide a path relative to a resources folder.
    [FolderPath(ParentFolder = "Assets/Resources")]
    public string ResourcePath;

    // By setting AbsolutePath to true, the FolderPath will provide an absolute path instead.
    [FolderPath(AbsolutePath = true)]
    [BoxGroup("Conditions")]
    public string AbsolutePath;

    // FolderPath can also be configured to show an error, if the provided path is invalid.
    [FolderPath(RequireExistingPath = true)]
    [BoxGroup("Conditions")]
    public string ExistingPath;

    // By default, FolderPath will enforce the use of forward slashes. It can also be configured to use backslashes instead.
    [FolderPath(UseBackslashes = true)]
    [BoxGroup("Conditions")]
    public string Backslashes;

    // FolderPath also supports member references and attribute expressions with the $ symbol.
    [FolderPath(ParentFolder = "$DynamicParent")]
    [BoxGroup("Member referencing")]
    public string DynamicFolderPath;

    [BoxGroup("Member referencing")]
    public string DynamicParent = "Assets/Plugins/Sirenix";

    // FolderPath also supports lists and arrays.
    [FolderPath(ParentFolder = "Assets/Plugins/Sirenix")]
    [BoxGroup("Lists")]
    public string[] ListOfFolders;
}

2.10 HideInInlineEditors

如果对象被 InlineEditor 特性绘制,则该对象在 Inspector 窗口中隐藏。

补充 InlineEditor 特性:将继承 UnityEngine.Object 的类(如 ScriptableObject)的详细信息显示在 Inspector 窗口。

image-20240718025035866

​ 数据结构类:

using UnityEngine;

#nullable disable
namespace Sirenix.OdinInspector.Editor.Examples
{
  public class MyInlineScriptableObject : ScriptableObject
  {
    [ShowInInlineEditors]
    public string ShownInInlineEditor;
    [HideInInlineEditors]
    public string HiddenInInlineEditor;
  }
}

​ 挂载的脚本:

// ShowAndHideInInlineEditorExampleComponent.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 ShowAndHideInInlineEditorExampleComponent : MonoBehaviour
{
#if UNITY_EDITOR // MyInlineScriptableObject is an example type and only exists in the editor
    [InfoBox("Click the pen icon to open a new inspector window for the InlineObject too see the differences these attributes make.")]
    [InlineEditor(Expanded = true)]
    public MyInlineScriptableObject InlineObject;
#endif
    
#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData()
    {
        InlineObject = ExampleHelper.GetScriptableObject<MyInlineScriptableObject>("Inline Object");
    }
    
    [OnInspectorDispose]
    private void CleanupData()
    {
        if (InlineObject != null) Object.DestroyImmediate(InlineObject);
    }
#endif
}

2.11 HideInTables

用于防止对象在使用 TableListAttribute 绘制的表中显示为列。

image-20240718025150278
// HideInTablesExampleComponent.cs

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

public class HideInTablesExampleComponent : MonoBehaviour
{
    public MyItem Item = new MyItem();

    [TableList]
    public List<MyItem> Table = new List<MyItem>() {
        new MyItem(),
        new MyItem(),
        new MyItem(),
    };

    [Serializable]
    public class MyItem
    {
        public string A;

        public int B;

        [HideInTables]
        public int Hidden;
    }
}

2.12 HideMonoScript

阻止某个类型的所有对象在 Inspector窗口中显示其成员。

image-20240718030213540

​ 数据结构类:

using UnityEngine;

#nullable disable
namespace Sirenix.OdinInspector.Editor.Examples
{
  public class ShowMonoScriptScriptableObject : ScriptableObject
  {
    public string Value;
  }
    
  [HideMonoScript]
  public class HideMonoScriptScriptableObject : ScriptableObject
  {
    public string Value;
  }
}

​ 挂载的脚本:

// HideMonoScriptExampleComponent.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 HideMonoScriptExampleComponent : MonoBehaviour
{
#if UNITY_EDITOR // HideMonoScriptScriptableObject and ShowMonoScriptScriptableObject are example types and only exist in the editor
    [InfoBox("Click the pencil icon to open new inspector for these fields.")]
    public HideMonoScriptScriptableObject Hidden;

    // The script will also be hidden for the ShowMonoScript object if MonoScripts are hidden globally.
    public ShowMonoScriptScriptableObject Shown;
#endif

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData() {
        Hidden = ExampleHelper.GetScriptableObject<HideMonoScriptScriptableObject>("Hidden");
        Shown  = ExampleHelper.GetScriptableObject<ShowMonoScriptScriptableObject>("Shown");
    }

    [OnInspectorDispose]
    private void CleanupData() {
        if (Hidden != null) Object.DestroyImmediate(Hidden);
        if (Shown != null) Object.DestroyImmediate(Shown);
    }
#endif
}

2.13 HideReferenceObjectPicker

将多态对象选择器隐藏在非 Unity 序列化引用类型的属性中。
当对象选择器隐藏时,可以右键单击并将实例设置为 null,以设置新值。

也可以使用 DisableContextMenu 特性来确保无法更改该值。

image-20240718030548801
// HideReferenceObjectPickerExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class HideReferenceObjectPickerExamplesComponent : SerializedMonoBehaviour
{
    [Title("Hidden Object Pickers")]
    [HideReferenceObjectPicker]
    public MyCustomReferenceType OdinSerializedProperty1 = new MyCustomReferenceType();

    [HideReferenceObjectPicker]
    public MyCustomReferenceType OdinSerializedProperty2 = new MyCustomReferenceType();

    [Title("Shown Object Pickers")]
    public MyCustomReferenceType OdinSerializedProperty3 = new MyCustomReferenceType();

    public MyCustomReferenceType OdinSerializedProperty4 = new MyCustomReferenceType();

    // Protip: You can also put the HideInInspector attribute on the class definition itself to hide it globally for all members.
    // [HideReferenceObjectPicker]
    public class MyCustomReferenceType
    {
        public int A;
        public int B;
        public int C;
    }
}

2.14 InlineEditor

将继承 UnityEngine.Object 的类(如 ScriptableObject)的详细信息显示在 Inspector 窗口。

  • InlineEditorModes inlineEditorMode = InlineEditorModes.GUIOnly

    绘制模式。

  • InlineEditorObjectFieldModes objectFieldMode = InlineEditorObjectFieldModes.Boxed

    绘制方式。

image-20240718031212511

2.15 Multiline

使用多行文本字段编辑字符串。

  • int lines = 3

    行数。

image-20240718031531320
// MultiLinePropertyExamplesComponent.cs

using Sirenix.OdinInspector;
using UnityEngine;

public class MultiLinePropertyExamplesComponent : MonoBehaviour
{
    // Unity's TextArea and Multiline attributes and Odin's MultiLineProperty attribute
    // are all very similar.
    // 
    // TextArea specifies a minimum and maximum number of lines. It will display at least
    // the minimum number of lines, but will expand with its content up to the maximum
    // number of lines, and display a scrollbar past that.
    // 
    // Multiline and MultiLineProperty are given a precise number of lines to occupy and
    // will never contract or expand based on contents; instead they display a scrollbar
    // if the content does not fit into the given number of lines.
    // 
    // Finally, unlike Multiline, Odin's MultiLineProperty can be applied to any member
    // type including fields, properties, method arguments, types, and so on.

    [TextArea(4, 10)]
    public string UnityTextAreaField = "";

    [Multiline(10)]
    public string UnityMultilineField = "";

    [Title("Wide Multiline Text Field", bold: false)]
    [HideLabel]
    [MultiLineProperty(10)]
    public string WideMultilineTextField = "";

    [InfoBox("Odin supports properties, but Unity's own Multiline attribute only works on fields.")]
    [ShowInInspector]
    [MultiLineProperty(10)]
    public string OdinMultilineProperty { get; set; }
}

2.16 PreviewField

绘制方形 ObjectField,预览对象类型。

  1. 拖拽对象到另一个对象,将交换值。
  2. 按住 ctrl 同时松开,将替换值。
  3. 按住 ctrl 并单击对象,将快速删除值。

可以从 Odin 首选项窗口选择性启用和全局自定义操作。

  • string previewGetter

    预览纹理的解析值。

  • float height

    预览窗口高度。

  • ObjectFieldAlignment alignment

    预览窗口对齐方式。

  • FilterMode filterMode = FilterMode.Bilinear

    预览纹理的过滤模式。

image-20240718032140205
// PreviewFieldExamplesComponent.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 PreviewFieldExamplesComponent : MonoBehaviour
{
    [PreviewField]
    public Object RegularPreviewField;

    [VerticalGroup("row1/left")]
    public string A, B, C;

    [HideLabel]
    [PreviewField(50, ObjectFieldAlignment.Right)]
    [HorizontalGroup("row1", 50), VerticalGroup("row1/right")]
    public Object D;

    [HideLabel]
    [PreviewField(50, ObjectFieldAlignment.Left)]
    [HorizontalGroup("row2", 50), VerticalGroup("row2/left")]
    public Object E;

    [VerticalGroup("row2/right"), LabelWidth(-54)]
    public string F, G, H;

    [PreviewField("preview", FilterMode.Bilinear)]
    public Object I;

    private Texture preview;

#if UNITY_EDITOR // Editor-related code must be excluded from builds
    [OnInspectorInit]
    private void CreateData() {
        RegularPreviewField = ExampleHelper.GetTexture();
        D                   = ExampleHelper.GetTexture();
        E                   = ExampleHelper.GetTexture();
        I                   = ExampleHelper.GetMesh();
        preview             = ExampleHelper.GetTexture();
    }

    [InfoBox(
                "These object fields can also be selectively enabled and customized globally " +
                "from the Odin preferences window.\n\n" +
                " - Hold Ctrl + Click = Delete Instance\n" +
                " - Drag and drop = Move / Swap.\n" +
                " - Ctrl + Drag = Replace.\n" +
                " - Ctrl + drag and drop = Move and override.")]
    [PropertyOrder(-1)]
    [Button(ButtonSizes.Large)]
    private void ConfigureGlobalPreviewFieldSettings() {
        Sirenix.OdinInspector.Editor.GeneralDrawerConfig.Instance.OpenInEditor();
    }
#endif
}

2.17 PolymorphicDrawerSettings

提供“多态类型”的绘制选项。

  • bool ShowBaseType

    是否显示基类。

  • bool ReadOnlyIfNotNullReference

    对象一旦被赋值,是否还可以改变。

  • NonDefaultConstructorPreference NonDefaultConstructorPreference

    指定如何处理非默认构造函数。

  • string CreateInstanceFunction

    指定自定义函数,用于创建所选对象的实例。

image-20240718033449480
// PolymorphicDrawerSettingsExampleComponent.cs

using System;
using Sirenix.OdinInspector;
using Sirenix.Serialization;
using Sirenix.Utilities;
using UnityEngine;

public class PolymorphicDrawerSettingsExampleComponent : MonoBehaviour
{
    [ShowInInspector]
    public IDemo<int> Default;
    
    [Title("Show Base Type"), ShowInInspector, LabelText("On")]
    [PolymorphicDrawerSettings(ShowBaseType = true)]
    public IDemo<int> ShowBaseType_On;
    
    [ShowInInspector, LabelText("Off")]
    [PolymorphicDrawerSettings(ShowBaseType = false)]
    public IDemo<int> ShowBaseType_Off;
    
    [Title("Read Only If Not Null Reference"), ShowInInspector, LabelText("On")]
    [PolymorphicDrawerSettings(ReadOnlyIfNotNullReference = true)]
    public IDemo<int> ReadOnlyIfNotNullReference_On;
    
    [ShowInInspector, LabelText("Off")]
    [PolymorphicDrawerSettings(ReadOnlyIfNotNullReference = false)]
    public IDemo<int> ReadOnlyIfNotNullReference_Off;
    
    [Title("Non Default Constructor Preference"), ShowInInspector, LabelText("Exclude")]
    [PolymorphicDrawerSettings(NonDefaultConstructorPreference = NonDefaultConstructorPreference.Exclude)]
    public IVector2<int> NonDefaultConstructorPreference_Ignore;
    
    [ShowInInspector, LabelText("Construct Ideal")]
    [PolymorphicDrawerSettings(NonDefaultConstructorPreference = NonDefaultConstructorPreference.ConstructIdeal)]
    public IVector2<int> NonDefaultConstructorPreference_ConstructIdeal;
    
    [ShowInInspector, LabelText("Prefer Uninitialized")]
    [PolymorphicDrawerSettings(NonDefaultConstructorPreference = NonDefaultConstructorPreference.PreferUninitialized)]
    public IVector2<int> NonDefaultConstructorPreference_PreferUninit;
    
    [ShowInInspector, LabelText("Log Warning")]
    [PolymorphicDrawerSettings(NonDefaultConstructorPreference = NonDefaultConstructorPreference.LogWarning)]
    public IVector2<int> NonDefaultConstructorPreference_LogWarning;
    
    [Title("Create Custom Instance"), ShowInInspector]
    [PolymorphicDrawerSettings(CreateInstanceFunction = nameof(CreateInstance))]
    public IVector2<int> CreateCustomInstance;
    
    private IVector2<int> CreateInstance(Type type)
    {
        Debug.Log("Constructor called for " + type + '.');
    
        if (typeof(SomeNonDefaultCtorClass) == type)
        {
            return new SomeNonDefaultCtorClass(485);
        }
    
        return type.InstantiateDefault(false) as IVector2<int>;
    }
    
    public interface IVector2<T>
    {
        T X { get; set; }
        T Y { get; set; }
    }
    
    [Serializable]
    public class SomeNonDefaultCtorClass : IVector2<int>
    {
        [OdinSerialize]
        public int X { get; set; }
    
        [OdinSerialize]
        public int Y { get; set; }
    
        public SomeNonDefaultCtorClass(int x)
        {
            this.X = x;
            this.Y = (x + 1) * 4;
        }
    }
    
    public interface IDemo<T>
    {
        T Value { get; set; }
    }
    
    [Serializable]
    public class DemoSOInt32 : SerializedScriptableObject, IDemo<int>
    {
        [OdinSerialize]
        public int Value { get; set; }
    }
    
    [Serializable]
    public class DemoSOInt32Target : SerializedScriptableObject, IDemo<int>
    {
        [OdinSerialize]
        public int Value { get; set; }
    
        public int target;
    }
    
    [Serializable]
    public class DemoSOFloat32 : SerializedScriptableObject, IDemo<float>
    {
        [OdinSerialize]
        public float Value { get; set; }
    }
    
    [Serializable]
    public class Demo<T> : IDemo<T>
    {
        [OdinSerialize]
        public T Value { get; set; }
    }
    
    [Serializable]
    public class DemoInt32Interface : IDemo<int>
    {
        [OdinSerialize]
        public int Value { get; set; }
    }
    
    public class DemoInt32 : Demo<int> { }
    
    public struct DemoStructInt32 : IDemo<int>
    {
        [OdinSerialize]
        public int Value { get; set; }
    }
}

2.18 TypeDrawerSettings

提供“类型”的绘制选项。

  • Type BaseType

    指定是否应使用基类型而不是所有类型。

  • TypeInclusionFilter Filter = TypeInclusionFilter.IncludeAll;

    过滤类型的方法。

image-20240718034227737
// TypeDrawerSettingsAttributeExampleComponent.cs

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

public class TypeDrawerSettingsAttributeExampleComponent : MonoBehaviour
{
    [ShowInInspector]
    public Type Default;

    [Title("Base Type"), ShowInInspector, LabelText("Set")]
    [TypeDrawerSettings(BaseType = typeof(IEnumerable<>))]
    public Type BaseType_Set;

    [ShowInInspector, LabelText("Not Set")]
    [TypeDrawerSettings(BaseType = null)]
    public Type BaseType_NotSet;

    [Title(nameof(TypeDrawerSettingsAttribute.Filter)), ShowInInspector, LabelText("Concrete Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes)]
    public Type Filter_Default;

    [ShowInInspector, LabelText("Concrete- && Generic Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes | TypeInclusionFilter.IncludeGenerics)]
    public Type Filter_Generics;

    [ShowInInspector, LabelText("Concrete- && Interface Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes | TypeInclusionFilter.IncludeInterfaces)]
    public Type Filter_Interfaces;

    [ShowInInspector, LabelText("Concrete- && Abstract Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes | TypeInclusionFilter.IncludeAbstracts)]
    public Type Filter_Abstracts;

    [ShowInInspector, LabelText("Concrete-, Abstract- && Generic Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes |
                                                                    TypeInclusionFilter.IncludeAbstracts |
                                                                    TypeInclusionFilter.IncludeGenerics)]
    public Type Filter_Abstracts_Generics;

    [ShowInInspector, LabelText("Concrete-, Interface- && Generic Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes |
                                                                    TypeInclusionFilter.IncludeInterfaces |
                                                                    TypeInclusionFilter.IncludeGenerics)]
    public Type Filter_Interfaces_Generics;

    [ShowInInspector, LabelText("Concrete-, Interface- && Abstract Types")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeConcreteTypes |
                                                                    TypeInclusionFilter.IncludeInterfaces |
                                                                    TypeInclusionFilter.IncludeAbstracts)]
    public Type Filter_Interfaces_Abstracts;

    [ShowInInspector, LabelText("All")]
    [TypeDrawerSettings(BaseType = typeof(IBaseGeneric<>), Filter = TypeInclusionFilter.IncludeAll)]
    public Type Filter_All;

    public interface IBaseGeneric<T>
    { }

    public interface IBase : IBaseGeneric<int>
    { }

    public abstract class Base : IBase
    { }

    public class Concrete : Base
    { }

    public class ConcreteGeneric<T> : Base
    { }

    public abstract class BaseGeneric<T> : IBase
    { }

    [CompilerGenerated]
    public class ConcreteGenerated : Base
    { }
}

2.19 SceneObjectsOnly

使目标对象在 Inspector 窗口中只能场景对象,限制拖拽的资源类型。

image-20240715004717713
// SceneAndAssetsOnlyExamplesComponent.cs

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

public class SceneAndAssetsOnlyExamplesComponent : MonoBehaviour
{
    [Title("Assets only")]
    [AssetsOnly]
    public List<GameObject> OnlyPrefabs;

    [AssetsOnly]
    public GameObject SomePrefab;

    [AssetsOnly]
    public Material MaterialAsset;

    [AssetsOnly]
    public MeshRenderer SomeMeshRendererOnPrefab;

    [Title("Scene Objects only")]
    [SceneObjectsOnly]
    public List<GameObject> OnlySceneObjects;

    [SceneObjectsOnly]
    public GameObject SomeSceneObject;

    [SceneObjectsOnly]
    public MeshRenderer SomeMeshRenderer;
}

2.20 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.21 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
}

2.22 Toggle

将对象放在开关组中绘制。

  • string toggleMemberName

    用于启用或禁用对象的任何 bool 字段或属性的名称。

  • bool CollapseOthersOnExpand = true

    如果为 true,其中一个打开,其他的开关组都将折叠显示。

image-20240718034704631
// ToggleExampleComponent.cs

using Sirenix.OdinInspector;
using System;
using UnityEngine;

public class ToggleExampleComponent : MonoBehaviour
{
    [Toggle("Enabled")]
    public MyToggleable Toggler = new MyToggleable();

    public ToggleableClass Toggleable = new ToggleableClass();

    [Serializable]
    public class MyToggleable
    {
        public bool Enabled;
        public int  MyValue;
    }

    // You can also use the Toggle attribute directly on a class definition.
    [Serializable, Toggle("Enabled")]
    public class ToggleableClass
    {
        public bool   Enabled;
        public string Text;
    }
}

2.23 ToggleGroup

将对象添加进单选框组。

  • string toggleMemberName

    启用或禁用 ToggleGroup 的任何 bool 字段或属性的名称。

  • float order = 0.0f

    单选框组的排序。

  • string groupTitle = null

    Inspector 窗口中显示的标题名称。

image-20240716043131827
// ToggleGroupExamplesComponent.cs

using Sirenix.OdinInspector;
using System;
using UnityEngine;

public class ToggleGroupExamplesComponent : MonoBehaviour
{
    // Simple Toggle Group
    [ToggleGroup("MyToggle")]
    public bool MyToggle;

    [ToggleGroup("MyToggle")]
    public float A;

    [ToggleGroup("MyToggle")]
    [HideLabel, Multiline]
    public string B;

    // Toggle for custom data.
    [ToggleGroup("EnableGroupOne", "$GroupOneTitle")]
    public bool EnableGroupOne = true;

    [ToggleGroup("EnableGroupOne")]
    public string GroupOneTitle = "One";

    [ToggleGroup("EnableGroupOne")]
    public float GroupOneA;

    [ToggleGroup("EnableGroupOne")]
    public float GroupOneB;

    // Toggle for individual objects.
    [Toggle("Enabled")]
    public MyToggleObject Three = new MyToggleObject();

    [Toggle("Enabled")]
    public MyToggleA Four = new MyToggleA();

    [Toggle("Enabled")]
    public MyToggleB Five = new MyToggleB();

    public MyToggleC[] ToggleList = new MyToggleC[] {
        new MyToggleC() { Test = 2f, Enabled = true, },
        new MyToggleC() { Test = 5f, },
        new MyToggleC() { Test = 7f, },
    };

    [Serializable]
    public class MyToggleObject
    {
        public bool Enabled;

        [HideInInspector]
        public string Title;

        public int A;
        public int B;
    }

    [Serializable]
    public class MyToggleA : MyToggleObject
    {
        public float C;
        public float D;
        public float F;
    }

    [Serializable]
    public class MyToggleB : MyToggleObject
    {
        public string Text;
    }

    [Serializable]
    public class MyToggleC
    {
        [ToggleGroup("Enabled", "$Label")]
        public bool Enabled;

        public string Label { get { return this.Test.ToString(); } }

        [ToggleGroup("Enabled")]
        public float Test;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1934676.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【 FPGA 线下免费体验馆】高端 AMD- xilinx 16 nm UltraScale +系列

在复杂的FPGA 开发的过程中&#xff0c;需要能够满足高速、高精度、多通道等的复杂应用。而一个简单的 FPGA 开发板是不具备这些的&#xff0c;因此需要用更高端&#xff0c;大容量&#xff0c;高速IO的 FPGA 芯片与其他硬件组成一个完整的系统开发。这里就产生了高端 FPGA 开发…

拍视频麦克风什么牌子好,什么麦克风音质好,无线麦克风品牌推荐

​当我们想要记录生活中的精彩瞬间&#xff0c;或是在工作中展现专业的一面时&#xff0c;声音的质量显得尤为重要。想象一下&#xff0c;在一间教室中&#xff0c;老师使用无线领夹麦克风&#xff0c;让每一个知识点都能准确无误地传达给学生&#xff1b;在一场激烈的体育赛事…

基于springboot新生宿舍管理系统

系统背景 在当今高等教育日益普及的时代背景下&#xff0c;高校作为知识传播与创新的重要基地&#xff0c;其基础设施的智能化管理显得尤为重要。新生宿舍作为大学生活的起点&#xff0c;不仅是学生日常生活与学习的重要场所&#xff0c;也是培养学生独立生活能力和团队合作精神…

从安装Node到TypeScript到VsCode的配置教程

从安装Node到TypeScript到VsCode的配置教程 1.下载Node安装包&#xff0c; 链接 2.双击安装包&#xff0c;选择安装路径&#xff0c;如下&#xff1a; 3.一直点击下一步&#xff0c;直至安装结束即可&#xff1a; 这个时候&#xff0c;node会默认配置好环境变量&#xff0c;并且…

Kotlin泛型实化

内联函数 reified实现 1. 内联函数 内联函数中的代码会在编译的时候自动被替换到调用它的地方&#xff0c;这样的话也就不存在什么泛型擦除的问题了&#xff0c;因为代码在编译之后会直接使用实际的类型来替代内联函数中的泛型声明。 2. reified关键字 在Kotlin中&#xff0…

webrtc QOS方法十三(视频渲染平滑)

一、背景介绍 视频渲染时间的确定需要考虑三方面的因素&#xff1a;网络抖动、网络延时、音视频同步 网络抖动&#xff1a;视频帧在网络上传输&#xff0c;会受到网络抖动的影响&#xff0c;不能收到立刻播放&#xff0c;需要进行适当的平滑 网络延时&#xff1a;一些报文在…

Axure 教程 | 设置文本框背景透明

​在AXURE软件中&#xff0c;部件样式可以编辑&#xff0c;但有时却无法满足所有个性化原型的需求。例如文本框部件&#xff0c;可以设置是否隐藏边框&#xff0c;但即使隐藏边框之后&#xff0c;文本框还会有白色的背景。 当界面需要一个无背景色的输入框时&#xff0c;对于完…

h5点击电话号跳转手机拨号

需要使用到h5的 <a>标签 我们首先在<head>标签中添加代码 <meta name"format-detection" content"telephoneyes"/>然后再想要的位置添加代码 <a href"tel:10086"> 点击拨打&#xff1a;10086 </a> 这样功能就实现…

QtC++ 设计模式(五)——状态模式

状态模式 序言理解源码 序言 设计模式只是一个抽象的设计模式方法&#xff0c;并不是一个固定使用的搭配&#xff0c;就算是普通switch语句&#xff0c;Map&#xff0c;乃至状态机都是状态模式的其中一种实现方法 状态模式看起来好像和策略模式差不多&#xff0c;主要是其的侧…

FastAPI -- 第三弹(自定义响应、中间件、代理、WebSockets)

路径操作的高级配置 OpenAPI 的 operationId from fastapi import FastAPIapp FastAPI()# 通过 operation_id 参数设置 app.get("/items/", operation_id"some_specific_id_you_define") async def read_items():return [{"item_id": "F…

基于Llama Index构建RAG应用

前言 Hello&#xff0c;大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者&#xff0c;本文参与活动是2024 DataWhale AI夏令营&#xff1b;&#x1f632; 在本文中作者将通过&#xff1a; Gradio、Streamlit和LlamaIndex介绍 LlamaIndex 构…

与VR融合的LED显示屏

随着技术的飞速发展&#xff0c;广告行业已经迎来了3.0时代&#xff0c;这标志着户外LED显示屏不再仅仅局限于空间展示&#xff0c;而是转向了一个全新的维度——“空间时间人”的场景化营销。这种转变要求LED显示屏行业不仅要增强显示技术&#xff0c;还要将消费者的个性化特征…

【中项】系统集成项目管理工程师-第2章 信息技术发展-2.1信息技术及其发展-2.1.1计算机软硬件与2.1.2计算机网络

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

Spring框架之DI依赖注入

Di(Dependence Injection)依赖注入,在spring框架负责创建bean对象时,动态地将依赖对象注入到其它对象中 一、什么是依赖注入。 我们在下面构建spring的过程中体会依赖注入&#xff1b; 从上面的图中我们知道&#xff0c;在ssm框架中服务层&#xff08;server&#xff09;无法直…

【操作系统】文件管理——文件共享与保护,文件系统的结构(个人笔记)

学习日期&#xff1a;2024.7.18 内容摘要&#xff1a;文件共享&#xff0c;文件保护&#xff0c;文件系统的层级结构和全局结构&#xff0c;虚拟文件系统 文件共享 操作系统提供的文件共享功能&#xff0c;可以让多个用户共享使用同一个文件。文件共享和文件复制是不一样的&a…

DP(6) | 完全背包 | Java | LeetCode 322, 179, 139 做题总结

322. 零钱兑换 我的错误答案 class Solution {public int coinChange(int[] coins, int amount) {int[][]dp new int [coins.length][amount1];for(int j0; j<amount; j) {if(coins[0] j){dp[0][coins[0]] 1;}}for(int i1; i<coins.length; i) {for(int j0; j<am…

实战篇(十一) : 拥抱交互的三维世界:利用 Processing 和 OpenGL 实现炫彩粒子系统

🌌 拥抱交互的三维世界:利用 Processing 和 OpenGL 实现炫彩粒子系统 在现代计算机图形学中,三维粒子系统是一个激动人心的领域。它不仅可以用来模拟自然现象,如烟雾、火焰和水流,还可以用来创造出令人叹为观止的视觉效果。在这篇文章中,我们将深入探讨如何使用 Proces…

Dify中的高质量索引模式实现过程

思考在什么情况下会使用到高质量索引模式呢?第1种情况是在知识库中上传文档,文档被拆分为段落后需要进行编码(增加);第2种情况是在召回测试的时候,需要对query进行编码(查询);第3种情况是当文档中的段落增加和更新时需要进行编码(增加和更新)。索引模式是针对知识库…

springboot 配置 spring data redis

1、在pom.xml引入父依赖spring-boot-starter-parent&#xff0c;其中2.7.18是最后一版支持java8的spring <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.18</…

汇编教程2

本教程主要教大家如何安装32位Linux虚拟机&#xff0c;为后续实验拆炸弹做准备 下载系统映像文件 以Ubuntu14.04.6系统为例 官方网站&#xff1a;下载地址 点击下载图中32位系统 如果官网进不去可以使用镜像网站 清华镜像网站&#xff1a;下载地址 进入之后找到下图中链接…