Skip to content

SplitPane HorizontalGroup and VerticalGroup

raeleus edited this page Feb 17, 2022 · 25 revisions

SplitPane and Horizontal/VerticalGroup are great ways to organize widgets. SplitPane allows the user to adjust the size of two widgets by dragging a border between the two. HorizontalGroup and VerticalGroup allow the user to add multiple child widgets one after the other in a line. It is most useful for allowing elements to wrap across a span.

SplitPaneStyle

The "handle" drawable is the divider that users must click to make adjustments to the split value. Make sure to supply a handle with enough width to allow the user to mouse over it. 1 pixel width is not enough. A simple square that can stretch in a direction should be good enough. Use a 9patch or TenPatch to add detail.
splitpane

SplitPane does not use a "default" style. Make sure to supply a "defaultHorizontal" and "defaultVertical" style if you plan to use both states of the widget. Horizontal means widgets on the left and right. Vertical means widgets on the top and bottom.
split-pane-horizontal split-pane-vertical

SplitPane Layout

This is a simple horizontal SplitPane that attaches two TextButtons. You can add any widget you desire into the two child slots.

TextButton textButton1 = new TextButton("test1", skin);
TextButton textButton2 = new TextButton("test2", skin);
SplitPane splitPane = new SplitPane(textButton1, textButton2, false, skin);
root.add(splitPane).growX();

qhUcyNz7bF

Notice that you can't actually make the widget smaller than the minWidth of the associated widgets. If that's important to you, stick them into ScrollPanes. ScrollPane has a minWidth of 0. This allows users to scroll the contents of the pane when you squish them beyond their minimum size.

TextButton textButton1 = new TextButton("test1", skin);
ScrollPane scrollPane1 = new ScrollPane(textButton1, skin);
scrollPane1.setFadeScrollBars(false);
TextButton textButton2 = new TextButton("test2", skin);
ScrollPane scrollPane2 = new ScrollPane(textButton2, skin);
scrollPane2.setFadeScrollBars(false);
SplitPane splitPane = new SplitPane(scrollPane1, scrollPane2, false, skin);
root.add(splitPane).growX();

X9Q8zi2S4N

If you don't care about allowing users to scroll the contents, you can just use Containers.

TextButton textButton1 = new TextButton("test1", skin);
Container container1 = new Container(textButton1);
container1.fill().minWidth(0);
TextButton textButton2 = new TextButton("test2", skin);
Container container2 = new Container(textButton2);
container2.fill().minWidth(0);
SplitPane splitPane = new SplitPane(container1, container2, false, skin);
root.add(splitPane).growX();

z1GOGJTg6J

You can set the initial split amount and the min/max. These are values from 0 to 1 with 1 being completely full.

splitPane.setSplitAmount(.75f);
splitPane.setMinSplitAmount(.25f);
splitPane.setMaxSplitAmount(.75f);

TbUyEfOAch

You can use an advanced listener to apply an arrow resize mouse icon. This is compatible with the LWJGL3 backend. If the widgets you use are not Touchable.enabled by default, make sure to set it.

public class ResizeArrowListener extends DragListener {
    private boolean draggingCursor;
    private boolean vertical;
    
    public ResizeArrowListener(boolean vertical) {
        this.draggingCursor = false;
        this.vertical = vertical;
    }
    
    @Override
    public void exit(InputEvent event, float x, float y, int pointer,
                     Actor toActor) {
        if (!draggingCursor && event.getListenerActor().equals(event.getTarget())) {
            Gdx.graphics.setSystemCursor(Cursor.SystemCursor.Arrow);
        }
    }
    
    @Override
    public void enter(InputEvent event, float x, float y, int pointer,
                      Actor fromActor) {
        if (!draggingCursor && event.getListenerActor().equals(event.getTarget())) {
            if (vertical) {
                Gdx.graphics.setSystemCursor(Cursor.SystemCursor.VerticalResize);
            } else {
                Gdx.graphics.setSystemCursor(Cursor.SystemCursor.HorizontalResize);
            }
        }
    }
    
    @Override
    public void dragStop(InputEvent event, float x, float y, int pointer) {
        Gdx.graphics.setSystemCursor(Cursor.SystemCursor.Arrow);
        draggingCursor = false;
    }
    
    @Override
    public void dragStart(InputEvent event, float x, float y,
                          int pointer) {
        if (!draggingCursor && event.getListenerActor().equals(event.getTarget())) {
            if (vertical) {
                Gdx.graphics.setSystemCursor(Cursor.SystemCursor.VerticalResize);
            } else {
                Gdx.graphics.setSystemCursor(Cursor.SystemCursor.HorizontalResize);
            }
            draggingCursor = true;
        }
    }
}
ResizeArrowListener resizeArrowListener = new ResizeArrowListener(false);
splitPane.addListener(resizeArrowListener);

X5bzzIqbsu

HorizontalGroup/VerticalGroup Layout

HorizontalGroup and VerticalGroup do not have a style at all because it is strictly used for layout very much like Table. But why would you want to use a HorizontalGroup instead of a Table? Horizontal group is a lot easier to add and remove elements to it. You don't have to think about rows or columns. You simply add actors to it.

letter-a letter-b letter-c letter-d

HorizontalGroup horizontalGroup = new HorizontalGroup();
table.add(horizontalGroup);

horizontalGroup.addActor(widgetA);
horizontalGroup.addActor(widgetB);
horizontalGroup.addActor(widgetC);
horizontalGroup.addActor(widgetD);

image

HorizontalGroups go from left to right. VerticalGroups go from top to bottom.

VerticalGroup verticalGroup = new VerticalGroup();
table.add(verticalGroup);

verticalGroup.addActor(widgetA);
verticalGroup.addActor(widgetB);
verticalGroup.addActor(widgetC);
verticalGroup.addActor(widgetD);

image

You can reverse the order of the elements by simply calling reverse().

horizontalGroup.reverse();

image

Notice that the width of each "cell" conforms to the minWidth of the widget in a HorizontalGroup. The same applies to the heights in a VerticalGroup.

large medium small

HorizontalGroup horizontalGroup = new HorizontalGroup();
table.add(horizontalGroup);

horizontalGroup.addActor(widgetLarge);
horizontalGroup.addActor(widgetMedium);
horizontalGroup.addActor(widgetSmall);

image

When the HorizontalGroup/VerticalGroup fills a large space, you can set the alignment of the contents. Beware that HorizontalGroup defaults to Align.left.

HorizontalGroup horizontalGroup = new HorizontalGroup();
table.add(horizontalGroup).grow();

horizontalGroup.addActor(widgetLarge);
horizontalGroup.addActor(widgetMedium);
horizontalGroup.addActor(widgetSmall);
horizontalGroup.align(Align.top);

image

horizontalGroup.align(Align.bottom);

image

Notice that each individual widget is not aligned. When your child widgets are not uniform size, you can set the row alignment of each child in the HorizontalGroup. It's important to know the difference between align() and rowAlign(). Set column alignment in VerticalGroup.

horizontalGroup.align(Align.center);
horizontalGroup.rowAlign(Align.bottom);

image

If you want to stretch the widgets to make up the difference in size, you can use grow().

horizontalGroup.grow();

image

Given an abundance of child widgets, you'll eventually run out of room and exceed the available space of the stage.

HorizontalGroup horizontalGroup = new HorizontalGroup();
table.add(horizontalGroup).grow();

horizontalGroup.addActor(widgetA);
horizontalGroup.addActor(widgetB);
horizontalGroup.addActor(widgetC);
horizontalGroup.addActor(widgetD);
horizontalGroup.addActor(widgetE);
horizontalGroup.addActor(widgetF);
horizontalGroup.addActor(widgetG);
horizontalGroup.addActor(widgetH);
horizontalGroup.addActor(widgetI);
horizontalGroup.addActor(widgetJ);
horizontalGroup.align(Align.center);

image

You can set wrap so that the elements will flow to the next available row given the available space.

horizontalGroup.wrap();

image

You can reverse the order of the rows or columns if you desire.

horizontalGroup.wrapReverse();

image

Let's talk about spacing and padding now. Spacing is the distance between each individual widget. In the case of HorizontalGroup, it's the horizontal space between each element on a row.

horizontalGroup.space(50);

image

Notice that it doesn't affect the vertical space between each row. To change that, you need to set the wrap space.

horizontalGroup.wrapSpace(20);

image

Padding is the extra space around the entire HorizontalGroup/VerticalGroup. This may not seem intuitive because of how padding/spacing can be used with table cells.

horizontalGroup.pad(50);

image

horizontalGroup.pad(150);

image

Further Steps

Proceed with the next chapter, 10 - Images or return to the table of contents.

Clone this wiki locally