How to use the PopUpTreeView component
The PopUpTreeView
class displays a button, that when triggered, renders the items from a hierarchical data collection in a pop-up tree view.
⚠️ Beta Notice: This component is still quite new. Some APIs may go through minor changes in upcoming releases.
The Basics
Start by creating a PopUpTreeView
control, and add it to the display list.
var popUpTreeView = new PopUpTreeView();
addChild(popUpTreeView);
Data provider
To render some data in the tree view, pass in a hierarchical collection that contains an object for each row.
var collection = new ArrayHierarchicalCollection([
{
text: "Node 1",
children: [
{
text: "Node 1A",
children: [
{ text: "Node 1A-I" },
{ text: "Node 1A-II" }
]
},
{ text: "Node 1B" },
]
},
{ text: "Node 2" },
{
text: "Node 3",
children: [
{ text: "Node 3A" },
{ text: "Node 3B" },
{ text: "Node 3C" }
]
}
]);
popUpTreeView.dataProvider = collection;
Set the collection's itemToChildren()
method to get the children from each branch that need to be rendered by the tree view.
collection.itemToChildren = (item:Dynamic) -> item.children;
Set the itemToText()
method to get the text from each item to display from the collection.
popUpTreeView.itemToText = (item:Dynamic) -> item.text;
Items in the collection are not required to be anonymous structures, like
{text: "Node 1B"}
in the example above. Class instances are allowed too (and encouraged as a best practice; you should prefer classes over anonymous structures). If you use a class, be sure to update the item parameter's type in theitemToChildren
anditemToText
functions so that the compiler can catch any errors.
Selection
Add an event listener for Event.CHANGE
to perform an action when the user selects a different item.
popUpTreeView.addEventListener(Event.CHANGE, popUpTreeView_changeHandler);
Check for the new value of the selectedItem
property in the listener.
function popUpTreeView_changeHandler(event:Event):Void {
var popUpTreeView = cast(event.currentTarget, PopUpTreeView);
trace("PopUpTreeView selectedItem change: " + popUpTreeView.selectedItem.text);
}
Alternatively, the value of the selectedLocation
property references the location of the items in the tree view's collection as an Array
of integers.
function popUpTreeView_changeHandler(event:Event):Void {
var popUpTreeView = cast(event.currentTarget, PopUpTreeView);
trace("PopUpTreeView selectedLocation change: " + popUpTreeView.selectedLocation);
}
Add or remove items
To add a new item at a specific location, pass an object to the data provider's addAt()
method.
var newItem = { text: "New Item" };
var newLocation = [2, 1];
popUpTreeView.dataProvider.addAt(newItem, newLocation);
In the example above, a new tab is added to the beginning.
Similarly, to remove an item, call remove()
or removeAt()
on the collection.
var locationToRemove = [2, 1];
popUpTreeView.dataProvider.removeAt(locationToRemove);
Item renderers
An item renderer is a Feathers UI component that displays a single item from a data collection inside a component like TreeView
and PopUpTreeView
. In other words, the TreeView
displayed by a PopUpTreeView
typically contains multiple item renderers — with each one rendering a different item from the collection.
Feathers UI provides a default HierarchicalItemRenderer
class, which can display data in many different ways that cover a variety of common use-cases. However, components like PopUpTreeView
also support custom item renderers, which allow developers to render the tree view's data in infinite unique ways.
Consider a collection of items with the following format.
{ name: "Pizza", icon: "https://example.com/img/pizza.png" }
While the default HierarchicalItemRenderer
class can easily display some text and an image, creating a custom item renderer for this simple data will be a good learning exercise.
A custom item renderer designed to display this data might use a Label
to display the text, and an AssetLoader
to display the image. The following example creates a DisplayObjectRecycler
which instantiates these components and adds them to a LayoutGroupItemRenderer
— a special base class for custom item renderers.
var recycler = DisplayObjectRecycler.withFunction(() -> {
var itemRenderer = new LayoutGroupItemRenderer();
var layout = new HorizontalLayout();
layout.gap = 6.0;
layout.paddingTop = 4.0;
layout.paddingBottom = 4.0;
layout.paddingLeft = 6.0;
layout.paddingRight = 6.0;
itemRenderer.layout = layout;
var openedToggle = new ToggleButton();
openedToggle.name = "openedToggle";
itemRenderer.addChild(openedToggle);
var icon = new AssetLoader();
icon.name = "loader";
itemRenderer.addChild(icon);
var label = new Label();
label.name = "label";
itemRenderer.addChild(label);
return itemRenderer;
});
Developers are not required to use the
LayoutGroupItemRenderer
class. In fact, a custom item renderer may be created from any OpenFL display object, including primitives likeopenfl.display.Sprite
and all other Feathers UI components.
Pass the DisplayObjectRecycler
to the itemRendererRecycler
property.
popUpTreeView.itemRendererRecycler = recycler;
So far, the DisplayObjectRecycler
creates the item renderer, but it doesn't understand how to interpret the data yet. A custom update()
method on the recycler can do that.
recycler.update = (itemRenderer:LayoutGroupItemRenderer, state:TreeViewItemState) -> {
var openedToggle = cast(itemRenderer.getChildByName("openedToggle"), ToggleButton);
var label = cast(itemRenderer.getChildByName("label"), Label);
var loader = cast(itemRenderer.getChildByName("loader"), AssetLoader);
openedToggle.visible = state.branch;
openedToggle.selected = state.branch && state.opened;
label.text = state.text;
loader.source = state.data.icon;
};
When the update()
method is called, it receives the item renderer and an TreeViewItemState
object. TreeViewItemState
has a number of useful properties.
data
is the item from the collection.branch
indicates if the item is a branch or not.enabled
indicates if the item renderer should be enabled or not.layoutIndex
is the position of the item within the layout.location
is the position of the item within the collection.opened
indicates if a branch is opened or not.owner
is theTreeView
that contains the item (Note: not thePopUpTreeView
).selected
is populated by comparing toselectedItem
.text
is populated usingitemToText()
In this case, the value of text
is displayed by the Label
, and the icon
field from data
(remember the example item from above, with name
and icon
fields) is displayed by the AssetLoader
. The values of branch
and opened
are used with a ToggleButton
to display whether a branch is opened or not. Obviously, we'll need an itemToText()
function to populate the text
value from the name
field.
popUpTreeView.itemToText = function(item:Dynamic):String {
return item.name;
};
It's always a good practice to provide a reset()
method to the DisplayObjectRecycler
, which will clean up a custom item renderer when it is no longer used by the PopUpTreeView
.
recycler.reset = (itemRenderer:LayoutGroupItemRenderer, state:TreeViewItemState) -> {
var label = cast(itemRenderer.getChildByName("label"), Label);
var loader = cast(itemRenderer.getChildByName("loader"), AssetLoader);
label.text = "";
loader.source = null;
};
Warning: A
DisplayObjectRecycler
without areset()
method could potentially cause memory leaks or other unexpected behavior, if the same data needs to be used again later.
Styles
A number of styles may be customized on the sub-components of a PopUpTreeView
component, including styles on the button and the tree view.
Button
The button in a PopUpTreeView
component is of type Button
. Its appearance may be customized globally in a theme, or it may be customized outside of a theme on an specific, individual PopUpTreeView
.
See How to use the
Button
component for complete details about which styles are available for the button.
Style button globally
Use the PopUpTreeView.CHILD_VARIANT_BUTTON
constant in a theme to provide a function that globally styles the buttons in all PopUpTreeView
components.
styleProvider.setStyleFunction(
Button,
PopUpTreeView.CHILD_VARIANT_BUTTON,
setPopUpTreeView_Button_Styles);
The function should use the following signature.
function setPopUpTreeView_Button_Styles(button:Button):Void {
// ... set styles here
}
Style the button in a specific PopUpTreeView
The buttonFactory
property may be used to customize the creation of an individual button.
popUpTreeView.buttonFactory = () -> {
var button = new Button();
// ... set styles here
return button;
};
TreeView
The tree view in a PopUpTreeView
component is of type TreeView
. Its appearance may be customized globally in a theme, or it may be customized outside of a theme on an specific, individual PopUpTreeView
.
See How to use the
TreeView
component for complete details about which styles are available for the tree view.
Style tree view globally
Use the PopUpTreeView.CHILD_VARIANT_TREE_VIEW
constant in a theme to provide a function that globally styles the tree views in all PopUpTreeView
components.
styleProvider.setStyleFunction(
TreeView,
PopUpTreeView.CHILD_VARIANT_TREE_VIEW,
setPopUpTreeView_TreeView_Styles);
The function should use the following signature.
function setPopUpTreeView_TreeView_Styles(treeView:TreeView):Void {
// ... set styles here
}
Style the tree view in a specific PopUpTreeView
The treeViewFactory
property may be used to customize the creation of an individual tree view.
popUpTreeView.treeViewFactory = () -> {
var treeView = new TreeView();
// ... set styles here
return treeView;
};