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

Unity Editor includeChildren为false时无法单独控制子Toggle问题

Unity批量重命名工具Toggle逻辑冲突修复

问题原因

现有渲染逻辑在OnGUI每帧执行时,都会无条件将单物体对应的include1数组值强制覆盖为和全局includeChildren变量一致,不管全局开关有没有被用户修改。这就导致全局开关为false时,用户手动点击单个Toggle修改的状态,会在下一帧渲染时被直接重置为false,完全无法手动调整单个物体的设置。

修复方案

  • 只在用户主动操作修改全局includeChildren开关的瞬间,才批量同步所有单个物体的Toggle值,全局开关状态不变时,不强制覆盖单个Toggle的用户设置
  • 全局开关为true时,将单个Toggle设为禁用状态,避免和全局全选逻辑冲突;全局开关为false时,解锁单个Toggle的编辑权限,支持用户手动勾选
  • 补全选中物体变化时的数组初始化逻辑,避免选中物体数量变化后出现数组索引越界异常

核心代码修改

1. 全局开关增加变化检测

替换原有全局Toggle渲染代码:

// 检测全局开关是否被用户主动修改
EditorGUI.BeginChangeCheck();
includeChildren = EditorGUILayout.Toggle("Include Children", includeChildren);
bool globalToggleChanged = EditorGUI.EndChangeCheck();

2. 替换循环内的单个Toggle逻辑

删除原有强制赋值的if/else代码块,替换为以下逻辑:

// 仅全局开关刚被修改时,才同步所有单个Toggle状态
if (globalToggleChanged)
{
    include1[i] = includeChildren;
}
// 全局开启时禁用单个Toggle编辑,全局关闭时允许手动调整
using (new EditorGUI.DisabledScope(includeChildren))
{
    include1[i] = EditorGUILayout.Toggle("Include Children", include1[i], GUILayout.ExpandWidth(true));
}

3. 补全选中物体变化时的数组初始化

修改OnSelectionChange方法,避免数组长度不匹配:

private void OnSelectionChange()
{
    objects = Selection.gameObjects;
    // 重新初始化单个Toggle数组,长度和当前选中物体匹配
    include1 = new bool[objects.Length];
    // 全局开关为开启状态时,所有单个Toggle默认设为true
    if (includeChildren)
    {
        for (int i = 0; i < include1.Length; i++)
        {
            include1[i] = true;
        }
    }
}

修复后完整脚本

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class RenameSelected : EditorWindow
{
    private static readonly Vector2Int size = new Vector2Int(500, 500);
    private string childrenPrefix;
    private int startIndex;
    private bool showPosition = false;
    private bool includeChildren = false;
    private bool[] include1;
    private GameObject[] objects;
    private Vector2 scrollPos;

    [MenuItem("GameObject/Rename Selected")]
    public static void Init()
    {
        EditorWindow window = GetWindow<RenameSelected>();
        window.minSize = size;
        window.maxSize = size;
    }

    private void OnSelectionChange()
    {
        objects = Selection.gameObjects;
        include1 = new bool[objects.Length];
        if (includeChildren)
        {
            for (int i = 0; i < include1.Length; i++)
            {
                include1[i] = true;
            }
        }
    }

    private void OnEnable()
    {
        objects = Selection.gameObjects;
        include1 = new bool[objects.Length];
    }

    public void OnGUI()
    {
        GUILayout.Space(10);
        childrenPrefix = EditorGUILayout.TextField("Rename prefix", childrenPrefix);
        startIndex = EditorGUILayout.IntField("Start index", startIndex);
        
        EditorGUI.BeginChangeCheck();
        includeChildren = EditorGUILayout.Toggle("Include Children", includeChildren);
        bool globalToggleChanged = EditorGUI.EndChangeCheck();

        if (objects.Length == 0)
        {
            showPosition = false;
        }
        GUILayout.Space(20);
        EditorGUILayout.GetControlRect(true, 16f, EditorStyles.foldout);
        Rect foldRect = GUILayoutUtility.GetLastRect();
        if (Event.current.type == EventType.MouseUp && foldRect.Contains(Event.current.mousePosition))
        {
            showPosition = !showPosition;
            GUI.changed = true;
            Event.current.Use();
        }

        showPosition = EditorGUI.Foldout(foldRect, showPosition, "Objects");
        GUILayout.Space(2);

        if (showPosition)
        {
            EditorGUI.indentLevel++;

            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
            for (int i = 0; i < objects.Length; i++)
            {
                EditorGUIUtility.labelWidth = 50;

                EditorGUILayout.BeginHorizontal();
                {
                    GUILayoutOption[] options = { GUILayout.MaxWidth(300.0f), GUILayout.MinWidth(300.0f) };
                    objects[i] = (GameObject)EditorGUILayout.ObjectField(i.ToString(), objects[i], typeof(GameObject), true, options);
                    EditorGUIUtility.labelWidth = 112;
                    
                    if (globalToggleChanged)
                    {
                        include1[i] = includeChildren;
                    }

                    using (new EditorGUI.DisabledScope(includeChildren))
                    {
                        include1[i] = EditorGUILayout.Toggle("Include Children", include1[i], GUILayout.ExpandWidth(true));
                    }
                }
                EditorGUILayout.EndHorizontal();
            }
            EditorGUILayout.EndScrollView();

            EditorGUI.indentLevel--;
        }

        GUILayout.FlexibleSpace();
        if (GUILayout.Button("Rename Objects"))
        {
            // 后续重命名逻辑可在此处实现,遍历objects时根据include1[i]判断是否获取子物体即可
        }

        Repaint();
    }
}

实现效果验证

  • 全局includeChildren勾选时:所有单个物体的子物体Toggle自动全选且置灰不可编辑,符合全局全选的预期
  • 全局includeChildren取消勾选时:单个Toggle恢复可编辑状态,用户可以自由勾选需要处理子物体的条目,不会被每帧强制重置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 21:06:28