using System; using System.Collections; using System.Collections.Generic; using DG.Tweening; using Ichni.RhythmGame; using Unity.VisualScripting; using UnityEngine; using UnityEngine.UI; namespace Ichni.Editor { public class Hierarchy : StaticWindow { public GameObject hierarchyTabPrefab; public RectTransform tabContainer; public Button addFolderButton; public List tabList; public Button expandButtom; public bool NeedExecute = false; private void Awake() { tabList = new List(); addFolderButton.onClick.AddListener(() => { ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List(), true, null); }); expandButtom.onClick.AddListener(Expand); rectTransform = this.GetComponent(); } public HierarchyTab GenerateTab(GameElement targetElement, GameElement parentElement) { HierarchyTab tab = Instantiate(hierarchyTabPrefab, tabContainer).GetComponent(); tab.SetTab(targetElement, parentElement); tabList.Add(tab); return tab; } public bool isExpand = false; private RectTransform rectTransform; public void Expand() { float originX = 225f; isExpand = !isExpand; // 用DOTween动画赋值 if (isExpand) { rectTransform.DOSizeDelta( new Vector2(rectTransform.sizeDelta.x * 2, rectTransform.sizeDelta.y), 0.5f); rectTransform.DOAnchorPos( new Vector2(originX * 2, rectTransform.anchoredPosition.y), 0.5f); enableButtonGroup.disableButton.GetComponent().DOAnchorPos( new Vector2( enableButtonGroup.disableButton.GetComponent().anchoredPosition.x * 3, enableButtonGroup.disableButton.GetComponent().anchoredPosition.y ), 0.5f); expandButtom.GetComponent().DOAnchorPos( new Vector2( expandButtom.GetComponent().anchoredPosition.x * 2, expandButtom.GetComponent().anchoredPosition.y ), 0.5f); } else { rectTransform.DOSizeDelta( new Vector2(rectTransform.sizeDelta.x / 2, rectTransform.sizeDelta.y), 0.5f); rectTransform.DOAnchorPos( new Vector2(originX, rectTransform.anchoredPosition.y), 0.5f); enableButtonGroup.disableButton.GetComponent().DOAnchorPos( new Vector2( enableButtonGroup.disableButton.GetComponent().anchoredPosition.x / 3, enableButtonGroup.disableButton.GetComponent().anchoredPosition.y ), 0.5f); expandButtom.GetComponent().DOAnchorPos( new Vector2( expandButtom.GetComponent().anchoredPosition.x / 2, expandButtom.GetComponent().anchoredPosition.y ), 0.5f); } } public ScrollRect scrollRect; public Vector2 vector2; public void FindTab(GameElement targetElement) { if (targetElement.connectedTab != null) { // 如果已经有Tab了,直接选中 targetElement.connectedTab.SelectGameElement(); getTabPos(targetElement.connectedTab); return; } targetElement.ScanAndAddEnableTypes(); if (!EditorManager.instance.ExpandWhileClick) { var tab = EditorManager.instance.uiManager.hierarchy.GenerateTab(targetElement, null); tab.SelectGameElement(); Destroy(tab.gameObject); EditorManager.instance.uiManager.hierarchy.tabList.Remove(tab); } else { StartCoroutine(TryGetTab(targetElement)); } } public IEnumerator TryGetTab(GameElement targetElement) { // 1. 向上找到最近的有Tab的祖先 Stack stack = new Stack(); GameElement current = targetElement; while (current != null && current.connectedTab == null) { stack.Push(current); current = current.parentElement; } // 2. 如果有Tab的祖先存在,依次展开回目标 HierarchyTab parentTab = current != null ? current.connectedTab : null; while (stack.Count > 0) { var elem = stack.Pop(); // 只展开父Tab,不直接生成Tab if (elem.parentElement != null && elem.parentElement.connectedTab != null) { if (!elem.parentElement.connectedTab.isExpanded) { elem.parentElement.connectedTab.ExpandOrFold(true); } else if (elem.parentElement.connectedTab.ienumerator is null) { elem.parentElement.connectedTab.ExpandOrFold(); elem.parentElement.connectedTab.ExpandOrFold(true);//合上再展开,这思路也是没谁了 } else { //他就在展开了,等下就好了 } yield return null; } // 等待当前elem的Tab生成 while (elem.connectedTab == null) { yield return null; } parentTab = elem.connectedTab; } // 3. 等待目标Tab实例化 while (targetElement.connectedTab is null) { yield return null; } yield return null; // 等待一帧,确保UI更新 getTabPos(targetElement.connectedTab); } void getTabPos(HierarchyTab finalTab) { // 修正定位算法 RectTransform tabRect = finalTab.GetComponent(); RectTransform containerRect = tabContainer; RectTransform viewportRect = scrollRect.viewport != null ? scrollRect.viewport : scrollRect.GetComponent(); // Tab相对于内容顶部的距离(正值为下,负值为上) float tabTop = -tabRect.anchoredPosition.y; float tabHeight = tabRect.rect.height; float contentHeight = containerRect.rect.height; float viewportHeight = viewportRect.rect.height; // 目标:让Tab居中(或尽量居中) float targetCenter = tabTop + tabHeight / 2f; float viewportCenter = viewportHeight / 2f; float scrollOffset = targetCenter - viewportCenter; // normalizedPosition = 1 - (scrollOffset / (contentHeight - viewportHeight)) float denominator = Mathf.Max(1f, contentHeight - viewportHeight); float normalized = 1f - Mathf.Clamp01(scrollOffset / denominator); scrollRect.verticalNormalizedPosition = normalized; finalTab.SelectGameElement(); } public GameElement upLoadElement = null; public IEnumerator TryGetElement() { NeedExecute = true; // 等待直到upLoadElement被赋值 if (upLoadElement == null) { yield return new WaitUntil(() => upLoadElement != null); } NeedExecute = false; upLoadElement = null; } } }