TreeView

  • All collections widgets support virtualization: gameobjects created only for the visible items.

  • Add Selectable component to use keyboard and gamepad navigation.

Attention

Different TreeView’s cannot display same nodes, unlike ListView, TileView, and Table.

Options

Options are almost same as the ListView, TileView and Table.

  • Data Source ObservableList<TreeNode<TItem>>

    Not available in the inspector window.

  • Deselect Collapsed Nodes bool

    Deselect nested nodes when parent node collapsed.

Get nodes

public TreeView Tree;

ObservableList<TreeNode<TreeViewItem>> nodes;

void Start()
{
   nodes = Tree.Nodes;
}

Get selected nodes

Tree.SelectedNodes.ForEach(x =>
{
   // do something with selected node
   Debug.Log(x.Item.Name);

   var component = Tree.GetItemComponent(x.Index);

   // not displayed component will be null
   if (component != null)
   {
      component.DoSomething();
   }
});

Add listeners

void AddListeners()
{
   Tree.NodeSelected.AddListener(ProcessSelectedNode);

   Tree.NodeDeselected.AddListener(ProcessDeselectedNode);
}

void ProcessSelectedNode(TreeNode<TreeViewItem> node)
{
   Debug.Log("selected: " + node.Item.Name);
}

void void ProcessDeselectedNode(TreeNode<TreeViewItem> node)
{
   Debug.Log("deselected: " + node.Item.Name);
}

Select node

Tree.SelectNode(nodes[1].Nodes[0]);

Select node with subnodes

Tree.SelectNodeWithSubnodes(nodes[1].Nodes[1]);

Deselect node

Tree.DeselectNode(nodes[1].Nodes[0]);

Deselect node with subnodes

Tree.DeselectNodeWithSubnodes(nodes[1].Nodes[1]);

Scroll to node

Tree.ScrollToAnimated(node);

Add node

var test_item = new TreeViewItem("added");
var test_node = new TreeNode<TreeViewItem>(test_item);
nodes.Add(test_node);

Hide nodes

nodes[1].IsVisible = false;
nodes[2].Nodes[1].IsVisible = false;

Collapse node

nodes[0].Nodes[0].IsExpanded = false;

Expand node

nodes[0].Nodes[0].IsExpanded = true;

Change node name

nodes[0].Item.Name = "Node renamed from code";
nodes[0].Nodes[1].Item.Name = "Another node renamed from code";

Sort

// Compare nodes by Name in ascending order
Comparison<TreeNode<TreeViewItem>> comparisonAsc = (x, y) => x.Item.Name.CompareTo(y.Item.Name);

// Compare nodes by Name in descending order
Comparison<TreeNode<TreeViewItem>> comparisonDesc = (x, y) => -x.Item.Name.CompareTo(y.Item.Name);

public void SortAsc()
{
   nodes.BeginUpdate();
   ApplyNodesSort(nodes, comparisonAsc);
   nodes.EndUpdate();
}

public void SortDesc()
{
   nodes.BeginUpdate();
   ApplyNodesSort(nodes, comparisonDesc);
   nodes.EndUpdate();
}

void ApplyNodesSort<T>(ObservableList<TreeNode<T>> nodes, Comparison<TreeNode<T>> comparison)
{
   // apply sort for current nodes
   nodes.Sort(comparison);
   // apply sort for child nodes
   nodes.ForEach(node =>
   {
      if (node.Nodes != null)
      {
         ApplyNodesSort(node.Nodes as ObservableList<TreeNode<T>>, comparison);
      }
   });
}

Filter nodes

public void Filter(string nameContains)
{
   // Maintains performance while items are added/removed/changed
   // by preventing the widgets from drawing
   // until the EndUpdate() method is called.
   nodes.BeginUpdate();

   SampleFilter(nodes, x => x.Name.Contains(nameContains));

   // Apply changes.
   nodes.EndUpdate();
}

bool SampleFilter(IObservableList<TreeNode<TreeViewItem>> nodes, Func<TreeViewItem,bool> filterFunc)
{
   return nodes.Count(x =>
   {
      var have_visible_children = (x.Nodes==null) ? false : SampleFilter(x.Nodes, filterFunc);
      x.IsVisible = have_visible_children || filterFunc(x.Item);
      return x.IsVisible;
   }) > 0;
}

Reset filter

public void ResetFilter()
{
   nodes.BeginUpdate();
   nodes.ForEach(SetVisible);
   nodes.EndUpdate();
}

void SetVisible(TreeNode<TreeViewItem> node)
{
   if (node.Nodes != null)
   {
      node.Nodes.ForEach(SetVisible);
   }

   node.IsVisible = true;
}

Clear nodes

public void Clear()
{
   nodes.Clear();
}