欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

unity treelistview

程序员文章站 2022-07-13 16:08:58
...

 

unity treelistview

unity treelistview

unity treelistview

使用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() { }
        
    }

}