152 lines
4.2 KiB
C#
152 lines
4.2 KiB
C#
|
#if UNITY_2019_4_OR_NEWER
|
|||
|
using System;
|
|||
|
using System.Linq;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEditor;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEditor.UIElements;
|
|||
|
using UnityEngine.UIElements;
|
|||
|
|
|||
|
namespace YooAsset.Editor
|
|||
|
{
|
|||
|
public class TreeViewer : VisualElement
|
|||
|
{
|
|||
|
public new class UxmlFactory : UxmlFactory<TreeViewer, UxmlTraits>
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
private readonly ListView _listView;
|
|||
|
private readonly List<TreeNode> _flattenList = new List<TreeNode>(1000);
|
|||
|
private readonly List<TreeNode> _rootList = new List<TreeNode>(100);
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 制作列表元素
|
|||
|
/// </summary>
|
|||
|
public Action<VisualElement> makeItem { get; set; }
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 绑定列表数据
|
|||
|
/// </summary>
|
|||
|
public Action<VisualElement, object> bindItem { get; set; }
|
|||
|
|
|||
|
|
|||
|
public TreeViewer()
|
|||
|
{
|
|||
|
this.style.flexShrink = 1f;
|
|||
|
this.style.flexGrow = 1f;
|
|||
|
|
|||
|
// 创建ListView
|
|||
|
_listView = new ListView();
|
|||
|
_listView.style.flexShrink = 1f;
|
|||
|
_listView.style.flexGrow = 1f;
|
|||
|
_listView.itemsSource = _flattenList;
|
|||
|
_listView.makeItem = MakeItemInternal;
|
|||
|
_listView.bindItem = BindItemInternal;
|
|||
|
this.Add(_listView);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 设置根节点数据
|
|||
|
/// </summary>
|
|||
|
public void SetRootItem(TreeNode rootNode)
|
|||
|
{
|
|||
|
_rootList.Add(rootNode);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 设置根节点数据
|
|||
|
/// </summary>
|
|||
|
public void SetRootItems(List<TreeNode> rootNodes)
|
|||
|
{
|
|||
|
_rootList.AddRange(rootNodes);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 清理数据
|
|||
|
/// </summary>
|
|||
|
public void ClearAll()
|
|||
|
{
|
|||
|
_rootList.Clear();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 重新绘制视图
|
|||
|
/// </summary>
|
|||
|
public void RebuildView()
|
|||
|
{
|
|||
|
_flattenList.Clear();
|
|||
|
foreach (var treeRoot in _rootList)
|
|||
|
{
|
|||
|
FlattenTree(treeRoot, 0);
|
|||
|
}
|
|||
|
_listView.Rebuild();
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 将树形结构扁平化为列表
|
|||
|
/// </summary>
|
|||
|
private void FlattenTree(TreeNode node, int depth)
|
|||
|
{
|
|||
|
_flattenList.Add(node);
|
|||
|
if (node.IsExpanded)
|
|||
|
{
|
|||
|
foreach (var child in node.Children)
|
|||
|
{
|
|||
|
FlattenTree(child, depth + 1);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private VisualElement MakeItemInternal()
|
|||
|
{
|
|||
|
var container = new VisualElement();
|
|||
|
container.style.flexDirection = FlexDirection.Row;
|
|||
|
|
|||
|
// 折叠按钮
|
|||
|
var toggle = new ToggleFoldout();
|
|||
|
toggle.text = string.Empty;
|
|||
|
toggle.name = "foldout";
|
|||
|
toggle.style.alignSelf = Align.Center;
|
|||
|
toggle.style.width = 15;
|
|||
|
toggle.style.height = 15;
|
|||
|
toggle.RegisterValueChangedCallback((ChangeEvent<bool> callback) =>
|
|||
|
{
|
|||
|
var treeNode = toggle.userData as TreeNode;
|
|||
|
treeNode.IsExpanded = toggle.value;
|
|||
|
RebuildView();
|
|||
|
});
|
|||
|
container.Add(toggle);
|
|||
|
|
|||
|
// 用户自定义元素
|
|||
|
if (makeItem != null)
|
|||
|
{
|
|||
|
makeItem.Invoke(container);
|
|||
|
}
|
|||
|
|
|||
|
return container;
|
|||
|
}
|
|||
|
private void BindItemInternal(VisualElement item, int index)
|
|||
|
{
|
|||
|
var treeNode = _flattenList[index];
|
|||
|
|
|||
|
// 设置折叠状态
|
|||
|
var toggle = item.Q<ToggleFoldout>("foldout");
|
|||
|
toggle.SetValueWithoutNotify(treeNode.IsExpanded);
|
|||
|
toggle.userData = treeNode;
|
|||
|
toggle.style.marginLeft = treeNode.GetDepth() * 15;
|
|||
|
|
|||
|
// 隐藏折叠按钮
|
|||
|
if (treeNode.Children.Count == 0)
|
|||
|
{
|
|||
|
toggle.style.visibility = Visibility.Hidden;
|
|||
|
}
|
|||
|
|
|||
|
// 用户自定义元素
|
|||
|
if (bindItem != null)
|
|||
|
{
|
|||
|
bindItem.Invoke(item, treeNode.UserData);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|