Unity树形控件(Tree View)的使用

时间:2024-03-19 11:08:55

Unity树形控件(Tree View)的使用

1.下载插件Tree View导入到工程中。下载地址:https://assetstore.unity.com/packages/tools/gui/tree-view-65364。
2.新建场景,新建Canvas,将Assets\Battlehub\UIControls\Prefabs\TreeView.prefab拖入Canvas下。

Unity树形控件(Tree View)的使用
3.点击【GameObject】【Create Empty】,创建一个空实体,命名为LoadTreeviewData。
4.创建LoadTreeviewData.cs脚本,打开编辑,将TreeViewDemo中的代码(类名除外)复制到脚本中(全部代码见后文)。
5.自定义数据给大家MyCustomData。
6.在LoadTreeviewData的Start()函数中添加Treeview数据,改写数据绑定ItemDataBinding和节点展开函数ItemExpanding。
7.将TreeView拖入变量框,运行即可。

using Battlehub.UIControls;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;

public class MyTreeview : MonoBehaviour {

    public TreeView TreeView;

    public static bool IsPrefab(Transform This)
    {
        if (Application.isEditor && !Application.isPlaying)
        {
            throw new InvalidOperationException("Does not work in edit mode");
        }
        return This.gameObject.scene.buildIndex < 0;
    }

    private void Start()
    {
        if (!TreeView)
        {
            Debug.LogError("Set TreeView field");
            return;
        }

        List<MyCustomData> dataItems = new List<MyCustomData>();
        dataItems.Add(new MyCustomData("宝成线", NodeType.RailwayLine));

        MyCustomData data = new MyCustomData("成昆线", NodeType.RailwayLine);
        data.childs.Add(new MyCustomData("成都段", NodeType.RailwaySection));
        data.childs.Add(new MyCustomData("云南段", NodeType.RailwaySection));


        dataItems.Add(data);
        dataItems.Add(new MyCustomData("京广线", NodeType.RailwayLine));

        //subscribe to events
        TreeView.ItemDataBinding += OnItemDataBinding;
        TreeView.SelectionChanged += OnSelectionChanged;
        TreeView.ItemsRemoved += OnItemsRemoved;
        TreeView.ItemExpanding += OnItemExpanding;
        TreeView.ItemBeginDrag += OnItemBeginDrag;

        TreeView.ItemDrop += OnItemDrop;
        TreeView.ItemBeginDrop += OnItemBeginDrop;
        TreeView.ItemEndDrag += OnItemEndDrag;

        //Bind data items
        TreeView.Items = dataItems;
    }

    private void OnItemBeginDrop(object sender, ItemDropCancelArgs e)
    {
        //object dropTarget = e.DropTarget;
        //if(e.Action == ItemDropAction.SetNextSibling || e.Action == ItemDropAction.SetPrevSibling)
        //{
        //    e.Cancel = true;
        //}

    }

    private void OnDestroy()
    {
        if (!TreeView)
        {
            return;
        }


        //unsubscribe
        TreeView.ItemDataBinding -= OnItemDataBinding;
        TreeView.SelectionChanged -= OnSelectionChanged;
        TreeView.ItemsRemoved -= OnItemsRemoved;
        TreeView.ItemExpanding -= OnItemExpanding;
        TreeView.ItemBeginDrag -= OnItemBeginDrag;
        TreeView.ItemBeginDrop -= OnItemBeginDrop;
        TreeView.ItemDrop -= OnItemDrop;
        TreeView.ItemEndDrag -= OnItemEndDrag;
    }

    private void OnItemExpanding(object sender, ItemExpandingArgs e)
    {
        MyCustomData dataItem = (MyCustomData)e.Item;
        if (dataItem.childs.Count > 0)
        {
            //Populate children collection
            e.Children = dataItem.childs;
        }
    }

    private void OnSelectionChanged(object sender, SelectionChangedArgs e)
    {
#if UNITY_EDITOR
        //Do something on selection changed (just syncronized with editor's hierarchy for demo purposes)
        UnityEditor.Selection.objects = e.NewItems.OfType<GameObject>().ToArray();
#endif
    }

    private void OnItemsRemoved(object sender, ItemsRemovedArgs e)
    {
        //Destroy removed dataitems
        for (int i = 0; i < e.Items.Length; ++i)
        {
            GameObject go = (GameObject)e.Items[i];
            if (go != null)
            {
                Destroy(go);
            }
        }
    }

    /// <summary>
    /// This method called for each data item during databinding operation
    /// You have to bind data item properties to ui elements in order to display them.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnItemDataBinding(object sender, TreeViewItemDataBindingArgs e)
    {
        MyCustomData dataItem = e.Item as MyCustomData;
        if (dataItem != null)
        {
            //We display dataItem.name using UI.Text 
            Text text = e.ItemPresenter.GetComponentInChildren<Text>(true);
            text.text = dataItem.name;

            //Load icon from resources
            Image icon = e.ItemPresenter.GetComponentsInChildren<Image>()[4];
            icon.sprite = Resources.Load<Sprite>("cube");

            //And specify whether data item has children (to display expander arrow if needed)
            if (dataItem.name != "TreeView")
            {
                e.HasChildren = dataItem.childs.Count > 0;
            }
        }
    }

    private void OnItemBeginDrag(object sender, ItemArgs e)
    {
        //Could be used to change cursor
    }

    private void OnItemDrop(object sender, ItemDropArgs e)
    {
        if (e.DropTarget == null)
        {
            return;
        }

        Transform dropT = ((GameObject)e.DropTarget).transform;

        //Set drag items as children of drop target
        if (e.Action == ItemDropAction.SetLastChild)
        {
            for (int i = 0; i < e.DragItems.Length; ++i)
            {
                Transform dragT = ((GameObject)e.DragItems[i]).transform;
                dragT.SetParent(dropT, true);
                dragT.SetAsLastSibling();
            }
        }

        //Put drag items next to drop target
        else if (e.Action == ItemDropAction.SetNextSibling)
        {
            for (int i = e.DragItems.Length - 1; i >= 0; --i)
            {
                Transform dragT = ((GameObject)e.DragItems[i]).transform;
                int dropTIndex = dropT.GetSiblingIndex();
                if (dragT.parent != dropT.parent)
                {
                    dragT.SetParent(dropT.parent, true);
                    dragT.SetSiblingIndex(dropTIndex + 1);
                }
                else
                {
                    int dragTIndex = dragT.GetSiblingIndex();
                    if (dropTIndex < dragTIndex)
                    {
                        dragT.SetSiblingIndex(dropTIndex + 1);
                    }
                    else
                    {
                        dragT.SetSiblingIndex(dropTIndex);
                    }
                }
            }
        }

        //Put drag items before drop target
        else if (e.Action == ItemDropAction.SetPrevSibling)
        {
            for (int i = 0; i < e.DragItems.Length; ++i)
            {
                Transform dragT = ((GameObject)e.DragItems[i]).transform;
                if (dragT.parent != dropT.parent)
                {
                    dragT.SetParent(dropT.parent, true);
                }

                int dropTIndex = dropT.GetSiblingIndex();
                int dragTIndex = dragT.GetSiblingIndex();
                if (dropTIndex > dragTIndex)
                {
                    dragT.SetSiblingIndex(dropTIndex - 1);
                }
                else
                {
                    dragT.SetSiblingIndex(dropTIndex);
                }
            }
        }
    }

    private void OnItemEndDrag(object sender, ItemArgs e)
    {
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.J))
        {
            TreeView.SelectedItems = TreeView.Items.OfType<object>().Take(5).ToArray();
        }
        else if (Input.GetKeyDown(KeyCode.K))
        {
            TreeView.SelectedItem = null;
        }
    }
}

enum NodeType { RailwayLine = 0, RailwaySection = 1, RailwaySegment = 2, RailwayStation = 3 }
class MyCustomData
{
    public List<MyCustomData> childs;
    public NodeType nodeType;
    public string name;
    public object tag;

    public MyCustomData(string na, NodeType nt)
    {
        childs = new List<MyCustomData>();
        name = na;
        nodeType = nt;
    }
}