unity treelistview
程序员文章站
2022-07-13 16:08:58
...
使用demo:
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour {
private void Awake()
{
var view = GetComponent<TreeView>();
view.Add<TreeView.Item>(0,1);
view.Add<TreeView.Item>(1, 66);
view.Add<TreeView.Item>(66, 6666);
view.Add<TreeView.Item>(66, 66666);
view.Add<TreeView.Item>(66, 66662);
view.Add<TreeView.Item>(1, 2);
view.Add<TreeView.Item>(2, 3);
view.Add<TreeView.Item>(0, 100000);
view.Add<TreeView.Item>(100000, 100001);
view.Add<TreeView.Item>(100001, 100002);
view.Add<TreeView.Item>(0, 200000);
view.Add<TreeView.Item>(200000, 2000001);
view.Add<TreeView.Item>(200000, 2000002);
view.Generate();
}
}
源码【没有优化】:
用到的类的链接:
QEventListener:https://blog.csdn.net/qq_17813937/article/details/72973009
QTreeNode:https://blog.csdn.net/qq_17813937/article/details/81184968
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
[DisallowMultipleComponent]
[RequireComponent(typeof(ScrollRect))]
public class TreeListView : MonoBehaviour {
public ScrollRect scrollRect;
public RectTransform[] backgroundStyle;
public Templet[] templet;
private Item[] backgroundParentItem;
private RectTransform conent;
private RectTransform Conent { get { return conent ??(conent= scrollRect.content); } }
Item root = new Item();
List<Item> nodes = new List<Item>();
public T Add<T>(int parent, int id)where T: Item, new()
{
var tmpNode = new T();
tmpNode.id = id;
nodes.Add(tmpNode);
root.Task(node => {
var item = node as Item;
if(item!=null && item.id == parent)
{
node.AddChild(tmpNode);
return true;
}
return false;
});
return tmpNode;
}
public T Add<T>(int parent, int id, Action<T> callback) where T : Item, new()
{
var tmp = new T();
tmp.id = id;
nodes.Add(tmp);
root.Task(node => {
var item = node as Item;
if (item != null && item.id == parent)
{
node.AddChild(tmp);
return true;
}
return false;
});
callback(tmp);
Create(tmp);
OpenChilds(root);
UpdateView();
return tmp;
}
/// <summary>
/// 单个删除
/// </summary>
/// <param name="id"></param>
public void Remove(int id)
{
List<Item> ds = new List<Item>();
root.Task(node => {
var item = (node as Item);
if (item.id == id)
{
item.Task(n => {
(n as Item).Delete();
nodes.Remove((n as Item));
return false;
});
ds.Add(item);
}
return false;
});
for(int i = 0, count = ds.Count; i < count; i++)
{
ds[i].Parent.RemoveChild(ds[i]);
}
ds.Clear();
}
public void Clear()
{
root.Task(node => {
(node as Item).Delete();
return false;
});
root.Clear();
nodes.Clear();
for (int i = 0, count = backgroundStyle.Length; i < count; i++)
backgroundStyle[i].sizeDelta = Vector2.zero;
}
public void Generate()
{
root.Task(node => {
var item = (node as Item);
if (node.Layer == 0) return false;
Create(item);
return false;
});
OpenChilds(root);
UpdateView();
}
private void UpdateView()
{
x = 0;
deltaTotal = 0;
UpdatePos(root);
UpdateSize();
UpdateBackgroundSize(root);
}
float deltaTotal;
private void UpdatePos(Item item)
{
if (item.instance!=null&& item.instance.gameObject.activeSelf)
{
item.instance.localPosition = new Vector3(0,deltaTotal,0);
var index = item.Layer - 1;
index = index >= templet.Length ? templet.Length - 1 : index;
if(item.Parent!=null && item == (item.Parent[item.Parent.GetChildsCount() - 1] as Item) && !item.IsOpen)
{
deltaTotal -= templet[index].endSpace;
}
else
{
if (item.IsOpen && item.GetChildsCount()>0)
{
deltaTotal -= templet[index + 1 >= templet.Length ? index : index + 1].startSpace;
}
else
{
deltaTotal -= templet[index].space;
}
}
deltaTotal -= item.instance.sizeDelta.y;
}
item.ForChilds((inde,node)=> {
UpdatePos(node as Item);
});
}
float x = 0;
private void UpdateSize()
{
for (int i = 0, count = templet.Length; i < count; i++)
x = Mathf.Max(x,templet[i].prefab.sizeDelta.x);
Conent.sizeDelta = new Vector2(x,-deltaTotal);
}
private void UpdateBackgroundSize(Item item)
{
if (item.GetChildsCount() > 0)
{
var start = (item[0] as Item).instance.localPosition.y;
var endobj = (item[item.GetChildsCount() - 1] as Item);
endobj = GetEnd(item);
QDebug.Log(endobj.id);
var end = endobj.instance.sizeDelta.y - endobj.instance.localPosition.y;
backgroundStyle[item.Layer].localPosition = new Vector3(0, start, 0);
backgroundStyle[item.Layer].sizeDelta = new Vector2(x, (start + end));
if (backgroundParentItem==null) backgroundParentItem = new Item[backgroundStyle.Length];
backgroundParentItem[item.Layer] = item;
item.ForChilds((index, node) => {
if ((node as Item).IsOpen)
{
UpdateBackgroundSize(node as Item);
}
});
}
if (backgroundParentItem == null) return;
for(int i=0,count= backgroundParentItem.Length; i < count; i++)
{
if (backgroundParentItem[i]!=null && !backgroundParentItem[i].IsOpen)
{
backgroundStyle[i].sizeDelta = Vector2.zero;
}
}
}
public Item GetEnd(Item item)
{
if (item.GetChildsCount() > 0)
{
var end = (item[item.GetChildsCount() - 1] as Item);
if (end.IsOpen) end = GetEnd(end);
return end;
}
return item;
}
private void OpenChilds(Item item)
{
item.Open();
if (item.Parent != null)
{
item.Parent.ForChilds((index, node) => {
if (item == node) return;
CloseChilds(node as Item);
});
}
item.ForChilds((index, node) => {
var child = (node as Item);
child.instance.gameObject.SetActive(true);
});
}
private void CloseChilds(Item item)
{
if (!item.IsOpen) return;
item.Close();
item.ForChilds((index, node) => {
(node as Item).instance.gameObject.SetActive(false);
CloseChilds(node as Item);
});
}
private void Create(Item item)
{
var index = item.Layer - 1;
item.instance = Instantiate(templet[index >= templet.Length ? templet.Length - 1 : index].prefab.gameObject).transform as RectTransform;
item.instance.gameObject.SetActive(false);
item.instance.SetParent(Conent, false);
item.Create();
QEventListener.Get(item.instance.gameObject).onInitializePotentialDrag = scrollRect.OnInitializePotentialDrag;
QEventListener.Get(item.instance.gameObject).onBeginDrag = scrollRect.OnBeginDrag;
QEventListener.Get(item.instance.gameObject).onDrag = scrollRect.OnDrag;
QEventListener.Get(item.instance.gameObject).onEndDrag = scrollRect.OnEndDrag;
QEventListener.Get(item.instance.gameObject).onClick = e => {
item.Click();
//if (item.GetChildsCount() <= 0) return;
if (item.IsOpen)
{
CloseChilds(item);
}
else
{
OpenChilds(item);
}
UpdateView();
};
}
[System.Serializable]
public struct Templet
{
public RectTransform prefab;
public int space;
public int startSpace;
public int endSpace;
}
[System.Serializable]
public class Item :QTreeNode{
public int id=0;
public RectTransform instance;
public Action onCreateComplete;
public bool IsOpen{ get; private set; }
public void Click()
{
OnClick();
}
public void Open()
{
IsOpen = true;
OpenChilds();
}
public void Close()
{
IsOpen = false;
CloseChilds();
}
public void Create()
{
OnCreate();
onCreateComplete?.Invoke();
onCreateComplete = null;
}
public void Delete()
{
if(instance !=null) Destroy(instance.gameObject);
OnDelete();
}
protected virtual void OnClick() { }
protected virtual void OnDelete() { }
protected virtual void OnCreate() { }
protected virtual void OpenChilds() { }
protected virtual void CloseChilds() { }
}
}
下一篇: 博客迁移