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
相关产品推荐
相关产品推荐

