UnityEditor.IMGUI.Controls 介紹
TreeView Examples project: 下載
TreeView Manual: 下載
TreeView API Documentation: 下載
MultiColumnHeader API Documentation: 下載
最近看項目中的編輯器模塊,發現大佬們寫的Unity編輯器工具非常優美,查閱代碼發現並沒有用很牛逼的插件,只是用原生的GUI和UnityEditor自帶控件製作而成。於是,向大佬學習,學習一下UnityEditor的控件。
UnityEditor.IMGUI.Controls相關控件API如下(官網可查閱):
TreeView(樹形控件+搜索控件)學習
相關API:
- TreeView:
-
TreeView是一個IMGUI控件,可以讓您爲編輯器創建樹視圖、列表視圖和多列表。它可以自定義行內容呈現、拖拽邏輯、選擇邏輯、搜索、排序和項目重命名
-
自定義樹形類繼承自TreeView,必須顯示調用TreeView中的有參構造,TreeView中不含有無參構造方法,無法隱式調用
-
BuildRoot():是一個需要被實現的抽象方法。該方法應該創建treeviewitem的完整樹並返回根目錄。這個方法和BuildRows一起實現TreeView的初始化工作。可以使用兩種不同的方法創建一個TreeView:(1)創建項目的根和完整樹;(2)創建根和行.方法1是默認的,因爲TreeView會自動處理構建行,祖先信息等等;對於非常大的數據集或經常更改的數據,方法2是可取的.每個TreeViewItem都需要用唯一的整數ID構造,對於相同的數據元素,ID需要保持一致,不管是否是拓展狀態。ID用於在樹中查找項目,用於選擇狀態、擴展狀態和導航。對於一個被合理初始化的TreeView,所有的treeviewitem都需要初始化“父”、“子”和“深度”屬性。根據樹的數據模型(Tree Model)可以有用的設置父和子的屬性或深度屬性,然後使用SetupParentsAndChildrenFromDepths或SetupDepthsFromParentsAndChildren方法在一次調用中設置所有行未初始化的屬性。
-
BuildRows():重寫該方法可以控制如何生成行。每當調用重載時或者每次擴展或收縮時,就會調用這個方法。構建行的默認實現負責根據完整的樹和項目的擴展狀態來緩存擴展的行。對於非常大的數據集或經常更改的數據,只需要創建TreeView的行,而不是完整的樹。在這種情況下,重寫該方法以手動構建行,如果遇到收縮的父節點,那麼父節點的後代就可以被忽略,設置項的孩子用CreateChildListforCollapsedParent()方法。當使用這種方法時,構建root應該只創建根TreeViewItem,也確保重寫GetAncestors()和GetDescendantsThatHaveChildren()和使用模型數據獲取這些信息,否則構建框架和擴大子樹將會失敗。
-
SetupDepthsFromParentsAndChildren():使用輸入TreeViewItem的深度爲其所有後代TreeViewItem設置正確的深度。
-
SetupParentsAndChildrenFromDepths():使用已設置的順序和深度值來初始化所有行的父和子屬性.
- TreeViewItem:
樹形View中單個Item - TreeViewState:
TreeViewState爲TreeView提供可序列化的狀態信息。這主要是用戶可以通過與TreeView進行交互來改變的狀態,例如選擇狀態,擴展狀態,導航狀態和滾動狀態.TreeViewState是唯一應該在TreeView中序列化/反序列化的狀態.TreeView本身不是可序列化的,應該從它所代表的樹數據中進行重構.這個類中包含的所有狀態都是由TreeView自身更新的。對這個狀態的訪問也可以通過TreeView API完成。 - SearchField:
搜索控件,對TreeView中TreeViewItem的displayName進行搜索,搜索後TreeView顯示搜索結果
使用方式:
searchField.downOrUpArrowKeyPressed += treeView.SetFocusAndEnsureSelectedItem;
treeView.searchString = searchField.OnToolbarGUI(treeView.searchString);
樹形控件效果圖:
TreeViewWindow(窗口類) :
using UnityEngine;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
public class TreeViewWindow : EditorWindow
{
TreeViewState viewState;
TestTreeView view;
SearchField searchField;
[MenuItem("TreeView學習/Text ccc")]
static void OpenWindow()
{
TreeViewWindow window = GetWindow<TreeViewWindow>();
window.Show();
}
private void OnEnable()
{
if (viewState == null)
viewState = new TreeViewState();
view = new TestTreeView(viewState);
searchField = new SearchField();
searchField.downOrUpArrowKeyPressed += view.SetFocusAndEnsureSelectedItem;
}
private void OnGUI()
{
DoToolbar();
DoTreeView();
DoBottomToolbar();
}
/// <summary>
/// 頭部搜索框
/// </summary>
private void DoToolbar()
{
GUILayout.BeginHorizontal(EditorStyles.toolbar);
view.searchString = searchField.OnToolbarGUI(view.searchString);
GUILayout.EndHorizontal();
}
/// <summary>
/// 內容樹
/// </summary>
private void DoTreeView()
{
Rect rect = new Rect(0, 20, position.width, position.height - 40);
this.view.OnGUI(rect);
}
/// <summary>
/// 底部toolbar
/// </summary>
private void DoBottomToolbar()
{
GUILayout.BeginArea(new Rect(0, position.height - 20, position.width, 20));
GUILayout.BeginHorizontal();
if (GUILayout.Button("展開所有"))
{
view.ExpandAll();
}
if (GUILayout.Button("收縮所有"))
{
view.CollapseAll();
}
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}
TestTreeView (樹形View):
using System.Collections.Generic;
using UnityEditor.IMGUI.Controls;
//重寫構造方法
//TreeView中不含有無參構造方法,無法隱式調用,必須顯示調用TreeView中的一個有參構造
public class TestTreeView : TreeView
{
public TestTreeView(TreeViewState state) : base(state)
{
Reload();
}
protected override TreeViewItem BuildRoot()
{
TreeViewItem root = new TreeViewItem(-1, -1, "root");
var allItems = new List<TreeViewItem>
{
new TreeViewItem {id = 1, depth = 0, displayName = "Animals"},
new TreeViewItem {id = 2, depth = 1, displayName = "Mammals"},
new TreeViewItem {id = 3, depth = 2, displayName = "Tiger"},
new TreeViewItem {id = 4, depth = 2, displayName = "Elephant"},
new TreeViewItem {id = 5, depth = 2, displayName = "Okapi"},
new TreeViewItem {id = 6, depth = 2, displayName = "Armadillo"},
new TreeViewItem {id = 7, depth = 1, displayName = "Reptiles"},
new TreeViewItem {id = 8, depth = 2, displayName = "Crocodile"},
new TreeViewItem {id = 9, depth = 2, displayName = "Lizard"},
new TreeViewItem {id = 11, depth = 0, displayName = "Animals"},
new TreeViewItem {id = 12, depth = 1, displayName = "Mammals"},
new TreeViewItem {id = 13, depth = 2, displayName = "Tiger"},
new TreeViewItem {id = 14, depth = 2, displayName = "Elephant"},
new TreeViewItem {id = 15, depth = 2, displayName = "Okapi"},
new TreeViewItem {id = 16, depth = 2, displayName = "Armadillo"},
new TreeViewItem {id = 17, depth = 1, displayName = "Reptiles"},
new TreeViewItem {id = 18, depth = 2, displayName = "Crocodile"},
new TreeViewItem {id = 19, depth = 2, displayName = "Lizard"},
new TreeViewItem {id = 21, depth = 0, displayName = "Animals"},
new TreeViewItem {id = 22, depth = 1, displayName = "Mammals"},
new TreeViewItem {id = 23, depth = 2, displayName = "Tiger"},
new TreeViewItem {id = 24, depth = 2, displayName = "Elephant"},
new TreeViewItem {id = 25, depth = 2, displayName = "Okapi"},
new TreeViewItem {id = 26, depth = 2, displayName = "Armadillo"},
new TreeViewItem {id = 27, depth = 1, displayName = "Reptiles"},
new TreeViewItem {id = 28, depth = 2, displayName = "Crocodile"},
new TreeViewItem {id = 29, depth = 2, displayName = "Lizard"},
};
SetupParentsAndChildrenFromDepths(root, allItems);
return root;
}
}