创建TreeItem使用的Prefab
场景中创建一个TreeView
全部代码
public class TreeView : MonoBehaviour
{
[SerializeField] private GameObject ItemPrefab;
public Action<TreeItem> OnItemClick;
public void LoadTree(IEnumerable<TreeItem> treeTtems)
{
LoadTree(treeTtems, transform);
}
private void LoadTree(IEnumerable<TreeItem> treeTtems, Transform _itemParentTran, TreeItem _itemParent = null)
{
foreach (TreeItem treeItem in treeTtems)
{
var itemTran = Instantiate(ItemPrefab, _itemParentTran).GetComponent<RectTransform>();
var itemButton = itemTran.Find("Content").GetComponent<Button>();
var headText = itemButton.transform.Find("Text").GetComponent<Text>();
headText.text = treeItem.Name;
if (treeItem.Height == 0) treeItem.Height = ItemPrefab.GetComponent<RectTransform>().sizeDelta.y;
treeItem.transform = itemTran;
treeItem.parent = _itemParent;
itemButton.onClick.AddListener(() =>
{
treeItem.IsOpen = !treeItem.IsOpen;
itemTran.DOSizeDelta(new Vector2(itemTran.sizeDelta.x, treeItem.GetRealHeight()), 0.2f);
treeItem.parent.ResetHeight();
OnItemClick?.Invoke(treeItem);
});
var childParent = itemTran.Find("Children");
if (treeItem.Children != null && treeItem.Children.Count() > 0)
{
LoadTree(treeItem.Children, childParent, treeItem);
}
if (treeItem.IsOpen) itemTran.sizeDelta = new Vector2(itemTran.sizeDelta.x, treeItem.GetRealHeight());
LayoutRebuilder.ForceRebuildLayoutImmediate(itemTran);
}
}
}
/// <summary>
/// TreeView的Item
/// </summary>
public class TreeItem
{
/// <summary>
/// TreeItem的<see cref="Transform"/>
/// </summary>
public Transform transform {
get; set; }
/// <summary>
/// TreeItem的父级
/// </summary>
public TreeItem parent {
get; set; }
public int Id {
get; set; }
public string Name {
get; set; }
/// <summary>
/// 子级集合
/// </summary>
public IEnumerable<TreeItem> Children {
get; set; }
/// <summary>
/// 是否展开/打开
/// </summary>
public bool IsOpen {
get; set; }
/// <summary>
/// 高度,如果没有指定则获取Prefab的高度
/// </summary>
public float Height {
get; set; }
}
public static class TreeItemBaseExtension
{
/// <summary>
/// 获取真实高度(包含子列表的高度)
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public static float GetRealHeight(this TreeItem item)
{
float tempHeight = 0f;
getChildrenHeight(item, ref tempHeight);
return tempHeight;
}
private static void getChildrenHeight(TreeItem treeItem, ref float height)
{
height += treeItem.Height;
if (treeItem.IsOpen && treeItem.Children != null)
{
foreach (var item in treeItem.Children)
{
getChildrenHeight(item, ref height);
}
}
}
/// <summary>
/// 刷新父级高度
/// </summary>
/// <param name="treeItem"></param>
public static void ResetHeight(this TreeItem treeItem)
{
if (treeItem != null)
{
var rect = treeItem.transform.GetComponent<RectTransform>();
rect.DOSizeDelta(new Vector2(rect.sizeDelta.x, treeItem.GetRealHeight()), 0.2f);
treeItem.parent.ResetHeight();
}
}
/// <summary>
/// 是否存在子列表
/// </summary>
/// <param name="treeItem"></param>
/// <returns></returns>
public static bool HasChild(this TreeItem treeItem)
{
return treeItem.Children != null;
}
}
调用
treeView.LoadTree(list);
treeView.OnItemClick += item =>
{
if (!item.HasChild())
Debug.Log(item.Name);
};