-
Notifications
You must be signed in to change notification settings - Fork 35
Tree and List
Using Trees and Lists is a great way to organize selectable data. List is usually used as an element of a SelectBox, however it can still be used on its own. Trees can organize data like an expandable file explorer.
The "background" drawable is the box that contains the entire contents of the widget. Do not add too much padding here or your selections will look a little odd.
Lists require a font to display their items. The user can click on any of the items to select it. To distinguish between selected and unselected items, set the "fontColorSelected" and "fontColorUnselected" color fields.
Another way to make selected items stand out is to specify a "selection" drawable. It could technically be a single pixel sized image that will be stretched, however you'll want to add some padding to your selection drawable if you find your text getting squished against the background. You can also add "over" and "down" drawables for when the user mouses over and clicks on these items.
If you just need a simple list with a few text options, it's easy enough to use #setItems() to do so.
List<String> list = new List(skin);
list.setItems(new String[] {"selection one", "selection two", "selection three"});
root.add(list);
List aligns to the left by default. There are times I like to set the alignment to the center especially if it's part of a SelectBox that is centered.
list.setAlignment(Align.center);
Little known fact: you can set a list to automatically select an entry as the user types the words. This requires the list to be clicked on or have keyboard focus assigned to it programmatically. Notice that you can completely type "aab" and selection will shift from "aaa" to "aab" appropriately.
List<String> list = new List(skin);
list.setItems(new String[] {"aaa", "aab", "bbb", "ccc", "ddd"});
list.setTypeToSelect(true);
root.add(list);
stage.setKeyboardFocus(list);
List accepts any kind of object as the array of items, but only implements them as text via Object#toString(). You can't add drawables or widgets to a list and expect them to display inside the list.
List list = new List(skin);
list.setItems(new Object[] {"string", new Label("label", skin), skin.getDrawable("button-normal")});
root.add(list);
Having a List of a specific type can be very useful when you need to use the selected Object to do a task.
final List<Drawable> list = new List(skin);
list.setItems(new Drawable[] {skin.getDrawable("checkbox"), skin.getDrawable("radio"), skin.getDrawable("button-normal")});
root.add(list);
root.row();
final Image image = new Image();
root.add(image).space(10);
list.addListener(new ChangeListener() {
@Override
public void changed(ChangeEvent event, Actor actor) {
image.setDrawable(list.getSelected());
}
});
The main purpose of the Tree widget is to expand and collapse data. To properly convey this, you need drawables as icons for the "plus" and "minus" fields. If you're trying to convey a file directory, for example, you'll use folder graphics to represent this. If it's a drop down bulleted list, simple arrows or plus/minus icons will be enough.
You can also specify mouse-over variations with plusOver and minusOver.
There are also fields for "background" and "over" if you want to add some style to each line. I don't find this incredibly useful unless you want the tree items to be selectable. In that case, make sure to fill something in for the "selection" field.
Implementing a Tree widget in your UI isn't exactly a straightforward process. You need to make a subclass of Tree.Node. Users must click the plus icon to expand that node's values.
@Override
public void create () {
...
Tree tree = new Tree(skin);
Label label = new Label("Folder", skin);
BasicNode node = new BasicNode(label);
label = new Label("child1", skin);
BasicNode node1 = new BasicNode(label);
node.add(node1);
label = new Label("child2", skin);
node1 = new BasicNode(label);
node.add(node1);
tree.add(node);
label = new Label("Folder2", skin);
node = new BasicNode(label);
label = new Label("child1", skin);
node1 = new BasicNode(label);
node.add(node1);
label = new Label("child2", skin);
node1 = new BasicNode(label);
node.add(node1);
tree.add(node);
root.add(tree);
stage.addActor(root);
}
public static class BasicNode extends Tree.Node {
public BasicNode(Actor actor) {
super(actor);
}
}
Why is Node so complicated? It is designed this way so that the generic type parameters don't need to be specified repeatedly. This can simplify your code tremendously.
@Override
public void create () {
...
Tree tree = new Tree(skin);
TextNode node = new TextNode("Folder");
TextNode node1 = new TextNode("child1");
node.add(node1);
node1 = new TextNode("child2");
node.add(node1);
tree.add(node);
node = new TextNode("Folder2");
node1 = new TextNode("child1");
node.add(node1);
node1 = new TextNode("child2");
node.add(node1);
tree.add(node);
root.add(tree);
stage.addActor(root);
}
public class TextNode extends Tree.Node<TextNode, String, Label> {
public TextNode(String text) {
super(new Label(text, skin));
setValue(text);
}
}
You can set the icon of a particular node.
node1.setIcon(skin.getDrawable("icon"));
Tree has various options on spacing.
tree.setIconSpacing(0, 10);
tree.setIndentSpacing(50);
tree.setYSpacing(10);
If you want your tree to have all nodes visible, you'll want to use Tree#expandAll(). Remember to use this after you define all your nodes or it will not work.
tree.expandAll();
Widgets often extend past the limited bounds of their parent and you need a way to contain them. Proceed with the next chapter, 06 - ScrollPane or return to the table of contents.
Getting Started
Windows
Linux
Mac
Features Manual
Colors
Fonts
Creating Bitmap Fonts
Creating FreeType Fonts
Creating Image Fonts
Drawables
Nine Patches
Ten Patches
Classes, Styles, and the Preview Panel
Custom Classes
Exporting
Importing
Saving / Loading
VisUI Skins
Tips and Tricks
TextraTypist Playground
Scene Composer
Scene Composer
Exporting a Scene
Modifying a Scene
Tutorials
Skin Composer Videos
From The Ground Up Series
Examples
Ray3K Skins