2025-11-13 16:24:49 +08:00
|
|
|
|
using System;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using TMPro;
|
|
|
|
|
|
using UnityEngine;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
using UnityEngine.SceneManagement;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
using UnityEngine.UI;
|
|
|
|
|
|
|
|
|
|
|
|
namespace SceneView
|
|
|
|
|
|
{
|
|
|
|
|
|
public class TreeViewNode : MonoBehaviour
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
public TreeViewNode? parent;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
public RectTransform? rectTransform;
|
|
|
|
|
|
public TextMeshProUGUI? text;
|
|
|
|
|
|
public Button? label;
|
|
|
|
|
|
public GameObject? child;
|
|
|
|
|
|
public RectTransform? childRectTransform;
|
|
|
|
|
|
public VerticalLayoutGroup? verticalLayout;
|
|
|
|
|
|
public Button? objectEnable;
|
|
|
|
|
|
public TextMeshProUGUI? objectText;
|
|
|
|
|
|
|
|
|
|
|
|
public float buttonHeight = 50;
|
|
|
|
|
|
|
|
|
|
|
|
private string originalText = "";
|
2025-11-18 18:45:14 +08:00
|
|
|
|
private GameObject? _targetGameObject; // 保存当前节点代表的GameObject
|
|
|
|
|
|
private bool _childrenGenerated = false; // 标记子节点和组件是否已经生成
|
|
|
|
|
|
private int _nodeDepth = 0; // 当前节点的深度
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
private void Awake()
|
|
|
|
|
|
{
|
|
|
|
|
|
CreateUI();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[ContextMenu("CreateUI")]
|
|
|
|
|
|
public void CreateUI()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取 RectTransform 组件,如果不存在则添加
|
|
|
|
|
|
if (rectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
rectTransform = GetComponent<RectTransform>();
|
2025-11-13 16:24:49 +08:00
|
|
|
|
if (rectTransform == null) rectTransform = gameObject.AddComponent<RectTransform>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
if (rectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to add RectTransform to the GameObject.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rectTransform.sizeDelta = new Vector2(0, buttonHeight);
|
|
|
|
|
|
rectTransform.anchorMin = Vector2.up;
|
|
|
|
|
|
rectTransform.anchorMax = Vector2.one;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
rectTransform.pivot = new Vector2(0.5f, 1); // 确保轴心点在顶部中央,便于布局
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
var buttonConfig = ButtonConfig.Default;
|
|
|
|
|
|
buttonConfig.RectConfig.Pivot = new Vector2(0.5f, 1);
|
|
|
|
|
|
buttonConfig.RectConfig.AnchorMin = new Vector2(0, 1);
|
|
|
|
|
|
buttonConfig.RectConfig.AnchorMax = new Vector2(1, 1);
|
|
|
|
|
|
buttonConfig.RectConfig.SizeDelta = new Vector2(0, buttonHeight);
|
2025-11-18 18:45:14 +08:00
|
|
|
|
buttonConfig.BackgroundColor = new Color(0.2f, 0.2f, 0.2f, 1f); // 默认背景色
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 创建按钮并检查是否已存在
|
|
|
|
|
|
if (label == null)
|
|
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var button = ControlUtilities.CreateButton(rectTransform, buttonConfig, null);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
label = button.button;
|
|
|
|
|
|
text = button.text;
|
|
|
|
|
|
if (text == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to get button text.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
text.alignment = TextAlignmentOptions.MidlineLeft;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
text.color = Color.white; // 确保文本颜色可见
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (objectEnable == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var button = ControlUtilities.CreateButton(rectTransform, buttonConfig, null);
|
|
|
|
|
|
objectEnable = button.button;
|
2025-11-13 16:24:49 +08:00
|
|
|
|
objectText = button.text;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
objectText.text = ""; // 默认文本为空,使用颜色作指示
|
|
|
|
|
|
objectText.color = Color.black; // 确保文本颜色可见
|
|
|
|
|
|
button.button.image.color = Color.yellow; // 默认颜色
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var rect = objectEnable.GetComponent<RectTransform>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
rect.anchorMin = Vector2.one;
|
|
|
|
|
|
rect.anchorMax = Vector2.one;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
rect.pivot = new Vector2(1, 1); // 右上角锚点
|
2025-11-08 14:03:17 +08:00
|
|
|
|
rect.sizeDelta = new Vector2(30, 30);
|
2025-11-18 18:45:14 +08:00
|
|
|
|
rect.anchoredPosition = new Vector2(-10, -10); // 距离右上角10像素
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查子对象是否存在
|
|
|
|
|
|
child = transform.Find("content")?.gameObject;
|
|
|
|
|
|
if (child == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
child = new GameObject("content");
|
|
|
|
|
|
child.transform.SetParent(rectTransform, false);
|
|
|
|
|
|
if (child == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to create or set parent for child content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
childRectTransform = child.AddComponent<RectTransform>();
|
|
|
|
|
|
if (childRectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to add RectTransform to the child content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
childRectTransform = child.GetComponent<RectTransform>();
|
|
|
|
|
|
if (childRectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to get RectTransform for the child content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保子内容一开始是隐藏的 (懒加载的初始状态)
|
|
|
|
|
|
child.SetActive(false);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
childRectTransform.anchorMin = new Vector2(0, 1);
|
|
|
|
|
|
childRectTransform.anchorMax = new Vector2(1, 1);
|
|
|
|
|
|
childRectTransform.pivot = new Vector2(0.5f, 1);
|
2025-11-18 18:45:14 +08:00
|
|
|
|
childRectTransform.offsetMax = new Vector2(0, -buttonHeight); // 占据主按钮以下的空间
|
|
|
|
|
|
childRectTransform.offsetMin = new Vector2(0, 0); // 确保底部没有额外偏移
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
verticalLayout = child.GetComponent<VerticalLayoutGroup>();
|
|
|
|
|
|
var sizeFitter = child.GetComponent<ContentSizeFitter>();
|
|
|
|
|
|
|
|
|
|
|
|
if (verticalLayout == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
verticalLayout = child.AddComponent<VerticalLayoutGroup>();
|
|
|
|
|
|
if (verticalLayout == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to add VerticalLayoutGroup to the child content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (sizeFitter == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
sizeFitter = child.AddComponent<ContentSizeFitter>();
|
|
|
|
|
|
if (sizeFitter == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Failed to add ContentSizeFitter to the child content.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 调整布局组参数,确保正确计算
|
|
|
|
|
|
verticalLayout.padding.left = (int)(buttonHeight * 0.5f); // 增加左边距以缩进
|
2025-11-08 14:03:17 +08:00
|
|
|
|
verticalLayout.padding.top = 2;
|
|
|
|
|
|
verticalLayout.padding.bottom = 4;
|
|
|
|
|
|
verticalLayout.spacing = 2;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
verticalLayout.childControlHeight = false; // 由ContentSizeFitter控制子节点高度
|
|
|
|
|
|
verticalLayout.childControlWidth = true; // 子节点宽度按父级宽度自适应
|
|
|
|
|
|
verticalLayout.childForceExpandHeight = false; // 不要强制展开高度
|
|
|
|
|
|
verticalLayout.childAlignment = TextAnchor.UpperLeft; // 确保子元素从上开始排列
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
sizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 修改为只初始化当前节点,不立即生成子内容
|
|
|
|
|
|
public IEnumerator InitializeNode(GameObject? targetObject, int depth = 0)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
_targetGameObject = targetObject;
|
|
|
|
|
|
_nodeDepth = depth;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 清除之前的监听器,避免重复
|
|
|
|
|
|
label?.onClick.RemoveAllListeners();
|
|
|
|
|
|
objectEnable?.onClick.RemoveAllListeners();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
if (targetObject == null) // 代表这是场景根节点
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
originalText = $"场景 {SceneManager.GetActiveScene().name}";
|
|
|
|
|
|
if (text) text.text = originalText + " →"; // 默认收拢,显示右箭头
|
|
|
|
|
|
label?.onClick.AddListener(OnExpand); // 场景节点点击展开自身
|
|
|
|
|
|
objectEnable?.gameObject.SetActive(false); // 场景节点没有Enable/Disable功能
|
|
|
|
|
|
yield break; // 场景节点不立即生成根对象,等待点击展开
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 过滤掉特定Canvas
|
|
|
|
|
|
if (targetObject == null || targetObject.name == CanvasControl.ViewCanvasName)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
yield break;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
originalText = GetIndentedName(targetObject.name, depth);
|
|
|
|
|
|
if (text != null) text.text = originalText + " →"; // 默认收拢,显示右箭头
|
|
|
|
|
|
|
|
|
|
|
|
// 注册展开事件
|
|
|
|
|
|
label?.onClick.AddListener(OnExpand);
|
|
|
|
|
|
|
|
|
|
|
|
// 注册对象启用/禁用事件
|
|
|
|
|
|
objectEnable?.gameObject.SetActive(true);
|
|
|
|
|
|
objectEnable?.onClick.AddListener(() => OnObjectEnable(_targetGameObject, objectEnable, objectText));
|
|
|
|
|
|
UpdateObjButton(_targetGameObject, objectEnable, objectText);
|
|
|
|
|
|
|
|
|
|
|
|
// 确保子内容一开始是隐藏的
|
|
|
|
|
|
if (child) child.SetActive(false);
|
|
|
|
|
|
yield return StartCoroutine(DelayedUpdateHeight()); // 初始化时异步更新高度
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 修改 OnExpand 方法以实现懒加载
|
|
|
|
|
|
private void OnExpand()
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
if (child == null)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
Debug.LogError("Child content not found.");
|
2025-11-08 14:03:17 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
CanvasControl.FocusGameObject=_targetGameObject;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 如果已经生成,直接切换显示状态
|
|
|
|
|
|
if (_childrenGenerated)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
ToggleExpansionVisuals();
|
|
|
|
|
|
StartCoroutine(DelayedUpdateHeight()); // 每次展开/收拢后异步更新高度
|
|
|
|
|
|
}
|
|
|
|
|
|
else // 如果子内容未生成,则异步生成
|
|
|
|
|
|
{
|
|
|
|
|
|
ToggleExpansionVisuals(); // 生成完成后再切换显示状态 (展开或根据后续逻辑)
|
|
|
|
|
|
// 在生成子节点之前,确保子内容容器是激活的
|
|
|
|
|
|
child.SetActive(true); // <--- 新增这行,在生成子节点之前激活容器
|
|
|
|
|
|
|
|
|
|
|
|
StartCoroutine(GenerateChildrenContent(_targetGameObject, _nodeDepth + 1, () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
_childrenGenerated = true;
|
|
|
|
|
|
// 注意:ToggleExpansionVisuals 会再次调用 child.SetActive()
|
|
|
|
|
|
// 如果是展开状态,它会保持 true。如果是收拢,则设置为 false。
|
|
|
|
|
|
StartCoroutine(DelayedUpdateHeight()); // 生成并展开后异步更新高度
|
|
|
|
|
|
}));
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
// 新增方法:生成子内容(组件和子GameObject)
|
|
|
|
|
|
private IEnumerator GenerateChildrenContent(GameObject? targetObject, int depth, Action? onComplete = null)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
ClearChildNodes(); // 在生成之前清空所有旧的子节点
|
|
|
|
|
|
|
|
|
|
|
|
if (targetObject == null) // 场景根节点,需要遍历根GameObject
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-13 16:24:49 +08:00
|
|
|
|
var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects();
|
|
|
|
|
|
foreach (var rootObject in rootObjects)
|
|
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
if (!rootObject || rootObject.name == CanvasControl.ViewCanvasName) continue;
|
|
|
|
|
|
|
|
|
|
|
|
var childNodeGO = new GameObject(rootObject.name);
|
|
|
|
|
|
var childNode = childNodeGO.AddComponent<TreeViewNode>();
|
2025-11-13 16:24:49 +08:00
|
|
|
|
childNode.transform.SetParent(childRectTransform, false);
|
|
|
|
|
|
childNode.parent = this;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
childNode.CreateUI(); // 确保UI元素已创建
|
|
|
|
|
|
// yield return StartCoroutine(childNode.InitializeNode(rootObject, depth)); // 浅初始化子节点
|
|
|
|
|
|
yield return null; // 每处理一个子节点就yield一次,分散帧压力
|
2025-11-13 16:24:49 +08:00
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
onComplete?.Invoke();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
yield break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 生成当前GameObject的组件按钮
|
2025-11-08 14:03:17 +08:00
|
|
|
|
var components = targetObject.GetComponents<Behaviour>();
|
|
|
|
|
|
foreach (var component in components)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (childRectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("childRectTransform is null");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var config = ButtonConfig.Default;
|
|
|
|
|
|
config.RectConfig.SizeDelta = new Vector2(0, 40);
|
2025-11-18 18:45:14 +08:00
|
|
|
|
config.BackgroundColor = component.enabled ? new Color(0.2f, 0.4f, 0.2f, 1f) : new Color(0.4f, 0.2f, 0.2f, 1f); // 根据组件启用状态设置颜色
|
|
|
|
|
|
config.Text = GetIndentedName(component.GetType().Name, depth, true); // 组件也需要缩进
|
|
|
|
|
|
config.TextColor = Color.white;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
var buttonBack = ControlUtilities.CreateButton(childRectTransform, config, null);
|
|
|
|
|
|
if (buttonBack.button == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("buttonBack.button is null");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var button = buttonBack.button;
|
|
|
|
|
|
var comp = component;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
button.onClick.AddListener(() => OnButtonClick(button, comp));
|
|
|
|
|
|
yield return null; // 每创建一个组件按钮就yield一次
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 遍历目标对象的所有子对象并创建新的TreeViewNode(浅初始化)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
foreach (Transform childTransform in targetObject.transform)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (childTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Debug.LogError("Child transform is null.");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
var childNodeGO = new GameObject(childTransform.gameObject.name);
|
|
|
|
|
|
var childNode = childNodeGO.AddComponent<TreeViewNode>();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
childNode.transform.SetParent(childRectTransform, false);
|
|
|
|
|
|
childNode.parent = this;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
childNode.CreateUI(); // 确保UI元素已创建
|
|
|
|
|
|
// yield return StartCoroutine(childNode.InitializeNode(childTransform.gameObject, depth)); // 浅初始化子节点
|
|
|
|
|
|
yield return null; // 每处理一个子节点就yield一次
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-13 16:24:49 +08:00
|
|
|
|
onComplete?.Invoke();
|
2025-11-18 18:45:14 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ToggleExpansionVisuals()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (child == null) return;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 切换 child 的激活状态
|
|
|
|
|
|
child.SetActive(!child.activeSelf);
|
|
|
|
|
|
|
|
|
|
|
|
if (text != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (child.activeSelf)
|
|
|
|
|
|
{
|
|
|
|
|
|
text.text = originalText + " ↓"; // 下三角符号表示展开
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
text.text = originalText + " →"; // 右三角符号表示收拢
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 异步更新高度,给布局系统一帧时间来计算
|
|
|
|
|
|
private IEnumerator DelayedUpdateHeight()
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 等待一帧,让 LayoutGroup 和 ContentSizeFitter 完成计算
|
|
|
|
|
|
yield return null;
|
|
|
|
|
|
InternalUpdateHeight();
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
private void InternalUpdateHeight()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (rectTransform == null || child == null || childRectTransform == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return; // Editor退出时可能为null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float currentChildHeight = 0f;
|
|
|
|
|
|
if (child.activeSelf && _childrenGenerated)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 强制重建 childRectTransform 的布局,以获取准确的 PreferredHeight
|
|
|
|
|
|
LayoutRebuilder.ForceRebuildLayoutImmediate(childRectTransform);
|
|
|
|
|
|
currentChildHeight = LayoutUtility.GetPreferredHeight(childRectTransform);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置主RectTransform的高度 = 按钮高度 + 子内容高度
|
|
|
|
|
|
rectTransform.sizeDelta = new Vector2(rectTransform.sizeDelta.x, buttonHeight + currentChildHeight);
|
|
|
|
|
|
|
|
|
|
|
|
// Debug.Log($"Node: {gameObject.name}, childActive: {child.activeSelf}, childrenGenerated: {_childrenGenerated}, currentChildHeight: {currentChildHeight}, finalNodeHeight: {rectTransform.sizeDelta.y}");
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有父节点,通知父节点重新计算布局
|
|
|
|
|
|
if (parent != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 强制重建父节点的 childRectTransform 的布局
|
|
|
|
|
|
LayoutRebuilder.ForceRebuildLayoutImmediate(parent.childRectTransform);
|
|
|
|
|
|
// 递归父节点异步更新高度
|
|
|
|
|
|
StartCoroutine(parent.DelayedUpdateHeight());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调整 GetIndentedName 以支持组件类型的缩进
|
|
|
|
|
|
private string GetIndentedName(string name, int depth, bool isComponent = false)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
|
|
|
|
|
var indent = "";
|
2025-11-18 18:45:14 +08:00
|
|
|
|
int baseIndent = depth; // GameObject的深度
|
|
|
|
|
|
if (isComponent) baseIndent++; // 组件比GameObject多一级缩进
|
2025-11-13 16:24:49 +08:00
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
// 增加额外的左边距,以产生层级感
|
|
|
|
|
|
for (var i = 0; i < baseIndent; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
indent += " ";
|
|
|
|
|
|
}
|
|
|
|
|
|
return $"{indent}{name}";
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void ClearChildNodes()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (childRectTransform != null)
|
2025-11-18 18:45:14 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 遍历并销毁所有子对象
|
|
|
|
|
|
for (int i = childRectTransform.childCount - 1; i >= 0; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
Destroy(childRectTransform.GetChild(i).gameObject);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnButtonClick(Button button, Behaviour component)
|
|
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
if (button == null || component == null) return;
|
2025-11-08 14:03:17 +08:00
|
|
|
|
|
|
|
|
|
|
// 切换组件的启用状态
|
|
|
|
|
|
var isEnabled = !component.enabled;
|
|
|
|
|
|
component.enabled = isEnabled;
|
|
|
|
|
|
// 根据组件的启用状态修改按钮背景颜色
|
2025-11-18 18:45:14 +08:00
|
|
|
|
button.image.color = isEnabled ? new Color(0.2f, 0.4f, 0.2f, 1f) : new Color(0.4f, 0.2f, 0.2f, 1f);
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 18:45:14 +08:00
|
|
|
|
private void OnObjectEnable(GameObject? gameObject, Button? button, TMP_Text? text)
|
2025-11-08 14:03:17 +08:00
|
|
|
|
{
|
2025-11-18 18:45:14 +08:00
|
|
|
|
if (gameObject == null || button == null || text == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
Debug.Log($"设置{gameObject.name} active = {!gameObject.activeSelf}");
|
2025-11-08 14:03:17 +08:00
|
|
|
|
gameObject.SetActive(!gameObject.activeSelf);
|
|
|
|
|
|
UpdateObjButton(gameObject, button, text);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateObjButton(GameObject gameObject, Button button, TMP_Text text)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (gameObject.activeSelf)
|
|
|
|
|
|
{
|
|
|
|
|
|
button.image.color = Color.green;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
text.text = "√";
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
button.image.color = Color.red;
|
2025-11-18 18:45:14 +08:00
|
|
|
|
text.text = "×";
|
2025-11-08 14:03:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-18 18:45:14 +08:00
|
|
|
|
|
|
|
|
|
|
}
|