You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Unity新UI ToolKit编辑器窗口中添加GameObject数组?

在UI ToolKit编辑器窗口实现GameObject数组控件

核心思路

UI ToolKit本身没有直接提供数组组件,但可以通过自定义绑定+复用Unity原生属性控件或定制ListView来实现类似Inspector的数组编辑功能,以下是两种实用方案:

方案一:复用SerializedProperty与PropertyField(推荐)

这种方式直接复用Unity内置的数组编辑UI,完全贴合原生Inspector体验,无需额外开发交互逻辑:

  1. 在编辑器窗口类中,获取目标对象的序列化对象和对应数组属性:
private SerializedObject targetSO;
private SerializedProperty gameObjectArrayProp;

void CreateGUI()
{
    // 替换为你的目标对象(比如ScriptableObject或MonoBehaviour实例)
    MyTargetComponent target = MyTargetComponent.Instance;
    targetSO = new SerializedObject(target);
    // 替换为你脚本中数组字段的名称
    gameObjectArrayProp = targetSO.FindProperty("myGameObjectArray");

    // 创建PropertyField并绑定属性
    var arrayField = new PropertyField(gameObjectArrayProp);
    arrayField.Bind(targetSO);
    rootVisualElement.Add(arrayField);
}

// 编辑器窗口更新时同步序列化对象
void Update()
{
    targetSO.Update();
}
  1. 生成的UI会和Inspector中的数组完全一致,支持添加/删除元素、拖拽GameObject赋值等所有原生交互。

方案二:自定义ListView实现(灵活定制)

如果需要完全自定义元素样式或交互逻辑,可以手动构建ListView:

  1. 先定义单个数组元素的UI结构:
private VisualElement CreateListItem(GameObject item)
{
    var container = new VisualElement();
    container.style.flexDirection = FlexDirection.Row;
    container.style.alignItems = Align.Center;

    // 用于选择GameObject的ObjectField
    var objectField = new ObjectField();
    objectField.objectType = typeof(GameObject);
    objectField.value = item;
    objectField.RegisterValueChangedCallback(evt =>
    {
        int index = listView.itemsSource.IndexOf(item);
        if (index >= 0)
        {
            (listView.itemsSource as List<GameObject>)[index] = evt.newValue as GameObject;
        }
    });

    // 删除按钮
    var deleteBtn = new Button(() =>
    {
        (listView.itemsSource as List<GameObject>).Remove(item);
        listView.Rebuild();
    });
    deleteBtn.text = "-";
    deleteBtn.style.width = 30;

    container.Add(objectField);
    container.Add(deleteBtn);
    return container;
}
  1. 初始化ListView并添加元素添加按钮:
private ListView listView;
private List<GameObject> gameObjectList = new List<GameObject>();

void CreateGUI()
{
    // 初始化ListView,指定数据源、元素高度和创建方法
    listView = new ListView(gameObjectList, 20, CreateListItem);
    listView.style.flexGrow = 1;
    rootVisualElement.Add(listView);

    // 添加元素的按钮
    var addBtn = new Button(() =>
    {
        gameObjectList.Add(null);
        listView.Rebuild();
    });
    addBtn.text = "Add GameObject";
    rootVisualElement.Add(addBtn);
}

这种方式可以完全控制UI样式,但需要手动处理数据与目标对象的同步逻辑。

注意事项

  • 使用PropertyField时,确保数组字段是公开的或带有[SerializeField]标签,否则SerializedProperty无法识别。
  • 编辑器窗口激活或目标对象变更时,需重新绑定属性,避免引用失效。
  • 自定义ListView方案中,若需持久化数据,要手动将gameObjectList同步到目标对象的数组字段中。

内容的提问来源于stack exchange,提问作者ouzari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 07:10:10