Files
ichni_Creator_Studio/Assets/Scripts/DynamicUI/Hierarchy/Hierarchy.cs

204 lines
8.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using DG.Tweening;
using Lean.Pool;
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<HierarchyTab> tabList;
public Button expandButtom;
public bool NeedExecute = false;
private void Awake()
{
tabList = new List<HierarchyTab>();
addFolderButton.onClick.AddListener(() =>
{
ElementFolder.GenerateElement("New Folder", Guid.NewGuid(), new List<string>(), true, null);
});
expandButtom.onClick.AddListener(Expand);
rectTransform = this.GetComponent<RectTransform>();
}
public HierarchyTab GenerateTab(GameElement targetElement, GameElement parentElement, bool animate = true)
{
if (targetElement.connectedTab != null) return targetElement.connectedTab;
HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent<HierarchyTab>();
tab.SetTab(targetElement, parentElement, animate);
tabList.Add(tab);
return tab;
}
public async Task<HierarchyTab> GenerateTabAsync(GameElement targetElement, GameElement parentElement)
{
if (targetElement.connectedTab != null) return targetElement.connectedTab;
HierarchyTab tab = LeanPool.Spawn(hierarchyTabPrefab, tabContainer).GetComponent<HierarchyTab>();
tab.SetTab(targetElement, parentElement);
tabList.Add(tab);
await Task.Yield();
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<RectTransform>().DOAnchorPos(
new Vector2(
enableButtonGroup.disableButton.GetComponent<RectTransform>().anchoredPosition.x * 3,
enableButtonGroup.disableButton.GetComponent<RectTransform>().anchoredPosition.y
), 0.5f);
expandButtom.GetComponent<RectTransform>().DOAnchorPos(
new Vector2(
expandButtom.GetComponent<RectTransform>().anchoredPosition.x * 2,
expandButtom.GetComponent<RectTransform>().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<RectTransform>().DOAnchorPos(
new Vector2(
enableButtonGroup.disableButton.GetComponent<RectTransform>().anchoredPosition.x / 3,
enableButtonGroup.disableButton.GetComponent<RectTransform>().anchoredPosition.y
), 0.5f);
expandButtom.GetComponent<RectTransform>().DOAnchorPos(
new Vector2(
expandButtom.GetComponent<RectTransform>().anchoredPosition.x / 2,
expandButtom.GetComponent<RectTransform>().anchoredPosition.y
), 0.5f);
}
}
public ScrollRect scrollRect;
public Vector2 vector2;
public void FindTab(GameElement targetElement)
{
if (targetElement.connectedTab != null)
{
targetElement.connectedTab.SelectGameElement();
getTabPos(targetElement.connectedTab);
return;
}
targetElement.ScanAndAddEnableTypes();
StartCoroutine(TryGetTab(targetElement));
}
public IEnumerator TryGetTab(GameElement targetElement)
{
// 1. 向上收集所有没有Tab的祖先
Stack<GameElement> stack = new Stack<GameElement>();
GameElement current = targetElement;
while (current != null && current.connectedTab == null)
{
stack.Push(current);
current = current.parentElement;
}
// 2. 从顶层祖先开始,逐层同步展开
while (stack.Count > 0)
{
var elem = stack.Pop();
var parentTab = elem.parentElement?.connectedTab;
if (parentTab != null)
{
if (!parentTab.isExpanded)
{
StartCoroutine(parentTab.ExpandSyncBatched());
yield return new WaitUntil(() => parentTab.isExpandDone);
}
else if (elem.connectedTab == null)
{
// 父节点已展开但当前元素缺失Tab刚添加或曾被折叠直接补生成
GenerateTab(elem, elem.parentElement, false);
}
}
else
{
if (elem.connectedTab == null)
GenerateTab(elem, null, false);
}
yield return null;
}
// 3. 最终确保目标Tab存在
if (targetElement.connectedTab == null)
{
GenerateTab(targetElement, targetElement.parentElement, false);
yield return null;
}
yield return null;
getTabPos(targetElement.connectedTab);
}
void getTabPos(HierarchyTab finalTab)
{
// 修正定位算法
RectTransform tabRect = finalTab.GetComponent<RectTransform>();
RectTransform containerRect = tabContainer;
RectTransform viewportRect = scrollRect.viewport != null ? scrollRect.viewport : scrollRect.GetComponent<RectTransform>();
// 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;
}
}
}