ArrayPropertyField Class

Description

Control for a serialized Array or List. It has many customization options.

public class ArrayPropertyField : ListControl, IEventHandler, ITransform, ITransitionAnimations, IExperimentalFeatures, IVisualElementScheduler, IResolvedStyle
Inheritance
Remarks

UI Toolkit's ListView covers many of ArrayPropertyField's use cases, but you may prefer this element sometimes. Use ArrayPropertyField when you need to go around bugs in ListView, or when you need the customization options. Use ListView when you need to take advantage of its virtualization system to handle thousands of elements with good performance.

More customizations are available by subclassing this element. See ArrayPropertyField's parent class for some of them (for example, to handle custom mouse drops).

Examples

Basic Usage:

class ACustomEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var root = new VisualElement();
        var list = new ArrayPropertyField(serializedObject.FindProperty("arrayField"));
        root.Add(list);
        return root;
    }
}

Configuration Options:

class ACustomEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var root = new VisualElement();
        var list = new ArrayPropertyField(serializedObject.FindProperty("field"));

        list.reorderable = false; // Make it non-reorderable.
        list.boxed = false; // Remove the box around the list.

        list.label = "custom label"; // Set the header's text
        list.headerMode = ListHeaderMode.Foldout; // Use a foldout in the header.
        list.headerMode = ListHeaderMode.Label; // Use a label in the header.
        list.headerMode = ListHeaderMode.None; // Hide the header.

        list.emptyListMessage = null; // Message for empty lists. Null hides it.
        list.showDragHandles = false; // Hide drag handles.
        list.showAlternatedBackgrounds = false; // Remove zebra-like backgrounds.
        list.showSeparators = true; // Show separator lines between items.

        // Add a little arrow to the add button.
        list.addButtonMode = AddButtonMode.WithOptions;
        // Hide the add button in the footer.
        list.addButtonMode = AddButtonMode.None;
        // Hide the remove buttons on each item.
        list.showRemoveButtons = false;

        // Show a button in the footer to remove the selected or the last item.
        list.showMainRemoveButton = true;
        // Enable item selection. Works great with the previous property.
        list.supportItemSelection = true;

        list.onAdd = (Rect buttonPosition) => { }; // Customize add behavior.
        list.onRemove = (int itemIndex) => { }; // Customize remove behavior.

        root.Add(list);
        return root;
    }
}

A custom example with ManagedReferenceFields for lists/arrays that use the SerializeReference attribute:

[System.Serializable] class ReferenceType1 { }

[System.Serializable] class ReferenceType2 { }

class ReferencesArrayContainer : ScriptableObject
{
    [SerializeReference]
    object[] m_ReferencesArray;
}

[CustomEditor(typeof(ReferencesArrayContainer))]
class ReferencesArrayContainerEditor : Editor
{
    public override VisualElement CreateInspectorGUI()
    {
        var root = new VisualElement();

        var arrayProperty = serializedObject.FindProperty("m_ReferencesArray");
        var list = new ArrayPropertyField
        (
            arrayProperty,
            // This constructor parameter is an optional item creation method.
            // We use it to return a ManagedReferenceField, which will update the
            // item's UI if the backing property changes type.
            i => new ManagedReferenceField(arrayProperty.GetArrayElementAtIndex(i))
        );

        // Add a little arrow to the add button.
        list.addButtonMode = AddButtonMode.WithOptions;
        // We need custom add functionality, otherwise it'll just add null items.
        list.onAdd = DisplayAddMenu;

        root.Add(list);
        return root;
    }

    private void DisplayAddMenu(Rect buttonPosition)
    {
        var menu = new GenericMenu();

        menu.AddItem(
            new GUIContent("Add Reference Type 1"),
            false,
            () => AddItemToArray(new ReferenceType1()));

        menu.AddItem(
            new GUIContent("Add Reference Type 2"),
            false,
            () => AddItemToArray(new ReferenceType2()));

        menu.DropDown(buttonPosition);
    }

    private void AddItemToArray(object newItem)
    {
        serializedObject.Update();
        var arrayProperty = serializedObject.FindProperty("m_ReferencesArray");

        arrayProperty.arraySize++;
        var newItemProperty =
            arrayProperty.GetArrayElementAtIndex(arrayProperty.arraySize - 1);
        newItemProperty.managedReferenceValue = newItem;

        serializedObject.ApplyModifiedProperties();
    }
}

Constructors

ArrayPropertyField(SerializedProperty, Func<Int32, VisualElement>)

Constructor. It receives a array/list SerializedProperty and an optional makeItem delegate. It still needs to be bound to work properly.

Fields

addButtonUssClassName

USS class name of the add button.

footerContentUssClassName

USS class name of the footer content.

headerContentUssClassName

USS class name of the element that contains the header's label or foldout.

headerFoldoutUssClassName

USS class name of the list's foldout.

headerLabelUssClassName

USS class name of the list's label.

removeButtonUssClassName

USS class name of the remove button.

ussClassName

USS class name of elements of this type.

withSeparatorsUSSClassName

USS class name of Lists with separators.

Properties

addButtonMode

The way to display the add button. Default Simple.

headerMode

The way to display the list's header. Default Foldout.

label

The text to show in the header. Set it to null to show the SerializedProperty's name.

onAdd

Set this callback to override what happens when clicking the add button. It gets passed the button's position.

onPopulateItemMenu

Set this callback to populate context menu for each list item. It gets passed the event, the item's context and its index.

onRemove

Set this callback to override what happens when clicking a remove button. It gets passed the item's index.

reorderable

Whether list items can be reordered by dragging.

showAlternatedBackgrounds

Whether to show backgrounds to differentiate between even and odd items. Default true.

showDragHandles

Whether to show handles in the list's items. Default true.

showMainRemoveButton

Whether to show a footer button to remove selected items from the list. If nothing is selected, it removes the last item. Set supportItemSelection true to enable item selection.

showRemoveButtons

Whether to show buttons to remove list items. Default true.

showSeparators

Whether to show lines and small paddings between items. Default false.

Inherited Members

ListControl.boxedUssClassName
ListControl.foldedUssClassName
ListControl.withHeaderUssClassName
ListControl.withFooterUssClassName
ListControl.draggingListUssClassName
ListControl.emptyUssClassName
ListControl.dropIndicatorUssClassName
ListControl.emptyMessageUssClassName
ListControl.headerUssClassName
ListControl.footerUssClassName
ListControl.itemUssClassName
ListControl.draggedItemUssClassName
ListControl.selectedItemUssClassName
ListControl.supportItemSelection
ListControl.selectedItem
ListControl.emptyListMessage
ListControl.boxed
ListControl.StartDraggingItem(Int32)
ListControl.GetListSize()
ListControl.SetListSize(Int32)
ListControl.GetListItem(Int32)
ListControl.SetHeaderVisibility(Boolean)
ListControl.SetHeaderContent(VisualElement)
ListControl.SetFooterVisibility(Boolean)
ListControl.SetFooterContent(VisualElement)
ListControl.CreateItemForIndex(Int32)
ListControl.IsReorderable()
ListControl.OnReorderDragPerformed(Int32, Int32)
ListControl.VerifyCustomDrag(Int32)
ListControl.OnCustomDragPerformed(Int32)

Extension Methods

UIToolkitExtensions.GetLocalRect(VisualElement)
UIToolkitExtensions.GetChildren<TElement>(VisualElement, List<TElement>, Func<TElement, Boolean>)
UIToolkitExtensions.GetFirstChild<TElement>(VisualElement, Func<TElement, Boolean>)
UIToolkitExtensions.ForEachChild<TElement>(VisualElement, Action<TElement>)