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

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鱼游戏开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值