https://blog.csdn.net/qq992817263/article/details/54925472
将文件夹放入 unity 中即可查看
作者 github 地址:https://github.com/ccUnity3d/TreeView
本人 gitee 地址(不用):https://gitee.com/hwm-ming/unity-tree-view
TreeViewControl(控制类)
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.UI;
///
/// 树形菜单控制器
///
public class TreeViewControl : MonoBehaviour
{
///
/// 当前树形菜单的数据源
///
[HideInInspector]
public List<TreeViewData> Data = null;
///
/// 树形菜单中元素的模板
///
public GameObject Template;
///
/// 树形菜单中元素的根物体
///
public Transform TreeItems;
///
/// 树形菜单的纵向排列间距
///
public int VerticalItemSpace = 2;
///
/// 树形菜单的横向排列间距
///
public int HorizontalItemSpace = 25;
///
/// 树形菜单中元素的宽度
///
public int ItemWidth = 230;
///
/// 树形菜单中元素的高度
///
public int ItemHeight = 35;
///
/// 所有子元素的鼠标点击回调事件
///
public delegate void ClickItemdelegate(GameObject item);
public event ClickItemdelegate ClickItemEvent;
//当前树形菜单中的所有元素
private List<GameObject> _treeViewItems;
//当前树形菜单中的所有元素克隆体(刷新树形菜单时用于过滤计算)
private List<GameObject> _treeViewItemsClone;
//树形菜单当前刷新队列的元素位置索引
private int _yIndex = 0;
//树形菜单当前刷新队列的元素最大层级
private int _hierarchy = 0;
//正在进行刷新
private bool _isRefreshing = false;
void Awake()
{
ClickItemEvent += ClickItemTemplate;
}
///
/// 鼠标点击子元素事件
///
public void ClickItem(GameObject item)
{
ClickItemEvent(item);
}
void ClickItemTemplate(GameObject item)
{
//空的事件,不这样做的话ClickItemEvent会引发空引用异常
}
///
/// 返回指定名称的子元素是否被勾选
///
public bool ItemIsCheck(string itemName)
{
for (int i = 0; i < _treeViewItems.Count; i++)
{
if (_treeViewItems[i].transform.Find("TreeViewText").GetComponent<Text>().text == itemName)
{
return _treeViewItems[i].transform.Find("TreeViewToggle").GetComponent<Toggle>().isOn;
}
}
return false;
}
///
/// 返回树形菜单中被勾选的所有子元素名称
///
public List<string> ItemsIsCheck()
{
List<string> items = new List<string>();
for (int i = 0; i < _treeViewItems.Count; i++)
{
if (_treeViewItems[i].transform.Find("TreeViewToggle").GetComponent<Toggle>().isOn)
{
items.Add(_treeViewItems[i].transform.Find("TreeViewText").GetComponent<Text>().text);
}
}
return items;
}
///
/// 生成树形菜单
///
public void GenerateTreeView()
{
//删除可能已经存在的树形菜单元素
if (_treeViewItems != null)
{
for (int i = 0; i < _treeViewItems.Count; i++)
{
Destroy(_treeViewItems[i]);
}
_treeViewItems.Clear();
}
//重新创建树形菜单元素
_treeViewItems = new List<GameObject>();
for (int i = 0; i < Data.Count; i++)
{
GameObject item = Instantiate(Template);
if (Data[i].ParentID == -1)
{
item.GetComponent<TreeViewItem>().SetHierarchy(0);
item.GetComponent<TreeViewItem>().SetParent(null);
}
else
{
TreeViewItem tvi = _treeViewItems[Data[i].ParentID].GetComponent<TreeViewItem>();
item.GetComponent<TreeViewItem>().SetHierarchy(tvi.GetHierarchy() + 1);
item.GetComponent<TreeViewItem>().SetParent(tvi);
tvi.AddChildren(item.GetComponent<TreeViewItem>());
}
item.transform.name = "TreeViewItem";
item.transform.Find("TreeViewText").GetComponent<Text>().text = Data[i].Name;
item.transform.SetParent(TreeItems);
item.transform.localPosition = Vector3.zero;
item.transform.localScale = Vector3.one;
item.transform.localRotation = Quaternion.Euler(Vector3.zero);
item.SetActive(true);
_treeViewItems.Add(item);
}
foreach (var item in _treeViewItems)
{
if (item.GetComponent<TreeViewItem>().GetChildrenNumber() == 0)
{
item.transform.Find("ContextButton").gameObject.SetActive(false);
}
}
}
///
/// 刷新树形菜单
///
public void RefreshTreeView()
{
//上一轮刷新还未结束
if (_isRefreshing)
{
return;
}
_isRefreshing = true;
_yIndex = 0;
_hierarchy = 0;
//复制一份菜单
_treeViewItemsClone = new List<GameObject>(_treeViewItems);
//用复制的菜单进行刷新计算
for (int i = 0; i < _treeViewItemsClone.Count; i++)
{
//已经计算过或者不需要计算位置的元素
if (_treeViewItemsClone[i] == null || !_treeViewItemsClone[i].activeSelf)
{
continue;
}
TreeViewItem tvi = _treeViewItemsClone[i].GetComponent<TreeViewItem>();
_treeViewItemsClone[i].GetComponent<RectTransform>().localPosition = new Vector3(tvi.GetHierarchy() * HorizontalItemSpace, _yIndex,0);
_yIndex += (-(ItemHeight + VerticalItemSpace));
if (tvi.GetHierarchy() > _hierarchy)
{
_hierarchy = tvi.GetHierarchy();
}
//如果子元素是展开的,继续向下刷新
if (tvi.IsExpanding)
{
RefreshTreeViewChild(tvi);
}
_treeViewItemsClone[i] = null;
}
//重新计算滚动视野的区域
float x = _hierarchy * HorizontalItemSpace + ItemWidth;
float y = Mathf.Abs(_yIndex);
transform.GetComponent<ScrollRect>().content.sizeDelta = new Vector2(x, y);
//清空复制的菜单
_treeViewItemsClone.Clear();
_isRefreshing = false;
}
///
/// 刷新元素的所有子元素
///
void RefreshTreeViewChild(TreeViewItem tvi)
{
for (int i = 0; i < tvi.GetChildrenNumber(); i++)
{
tvi.GetChildrenByIndex(i).gameObject.GetComponent<RectTransform>().localPosition = new Vector3(tvi.GetChildrenByIndex(i).GetHierarchy() * HorizontalItemSpace, _yIndex, 0);
_yIndex += (-(ItemHeight + VerticalItemSpace));
if (tvi.GetChildrenByIndex(i).GetHierarchy() > _hierarchy)
{
_hierarchy = tvi.GetChildrenByIndex(i).GetHierarchy();
}
//如果子元素是展开的,继续向下刷新
if (tvi.GetChildrenByIndex(i).IsExpanding)
{
RefreshTreeViewChild(tvi.GetChildrenByIndex(i));
}
int index = _treeViewItemsClone.IndexOf(tvi.GetChildrenByIndex(i).gameObject);
if (index >= 0)
{
_treeViewItemsClone[index] = null;
}
}
}
}
TreeViewItem(子项)
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
///
/// 树形菜单元素
///
public class TreeViewItem : MonoBehaviour
{
///
/// 树形菜单控制器
///
public TreeViewControl Controler;
///
/// 当前元素的子元素是否展开(展开时可见)
///
public bool IsExpanding = false;
//当前元素在树形图中所属的层级
private int _hierarchy = 0;
//当前元素指向的父元素
private TreeViewItem _parent;
//当前元素的所有子元素
private List<TreeViewItem> _children;
//正在进行刷新
private bool _isRefreshing = false;
void Awake()
{
// // 没有子元素隐藏下拉按钮
// if (GetChildrenNumber() == 0)
// {
// transform.Find("ContextButton").gameObject.SetActive(false);
// }
//上下文按钮点击回调
transform.Find("ContextButton").GetComponent<Button>().onClick.AddListener(ContextButtonClick);
transform.Find("TreeViewButton").GetComponent<Button>().onClick.AddListener(delegate () {
Controler.ClickItem(gameObject);
});
}
///
/// 点击上下文菜单按钮,元素的子元素改变显示状态
///
void ContextButtonClick()
{
//上一轮刷新还未结束
if (_isRefreshing)
{
return;
}
_isRefreshing = true;
if (IsExpanding)
{
transform.Find("ContextButton").GetComponent<RectTransform>().localRotation = Quaternion.Euler(0, 0, 90);
IsExpanding = false;
ChangeChildren(this, false);
}
else
{
transform.Find("ContextButton").GetComponent<RectTransform>().localRotation = Quaternion.Euler(0, 0, 0);
IsExpanding = true;
ChangeChildren(this, true);
}
//刷新树形菜单
Controler.RefreshTreeView();
_isRefreshing = false;
}
///
/// 改变某一元素所有子元素的显示状态
///
void ChangeChildren(TreeViewItem tvi, bool value)
{
for (int i = 0; i < tvi.GetChildrenNumber(); i++)
{
tvi.GetChildrenByIndex(i).gameObject.SetActive(value);
if (tvi.GetChildrenByIndex(i).IsExpanding)
{
ChangeChildren(tvi.GetChildrenByIndex(i), value);
}
}
}
#region 属性访问
public int GetHierarchy()
{
return _hierarchy;
}
public void SetHierarchy(int hierarchy)
{
_hierarchy = hierarchy;
}
public TreeViewItem GetParent()
{
return _parent;
}
public void SetParent(TreeViewItem parent)
{
_parent = parent;
}
public void AddChildren(TreeViewItem children)
{
if (_children == null)
{
_children = new List<TreeViewItem>();
}
_children.Add(children);
}
public void RemoveChildren(TreeViewItem children)
{
if (_children == null)
{
return;
}
_children.Remove(children);
}
public void RemoveChildren(int index)
{
if (_children == null || index < 0 || index >= _children.Count)
{
return;
}
_children.RemoveAt(index);
}
public int GetChildrenNumber()
{
if (_children == null)
{
return 0;
}
return _children.Count;
}
public TreeViewItem GetChildrenByIndex(int index)
{
if (index >= _children.Count)
{
return null;
}
return _children[index];
}
#endregion
}
TreeViewData(数据类)
///
/// 树形菜单数据
///
public class TreeViewData
{
///
/// 数据内容
///
public string Name;
///
/// 数据所属的父ID
///
public int ParentID;
}