How to create a responsive layout in JavaFX
Some days ago I was asked at twitter about a responsive layout problem in JavaFX. Based on my work that I did with ResponsiveFX I was asked how I would create a specific responsive behavior.
In this special case a image and text should next to each other on a desktop. In a smaller (mobile) version the text should be placed under the image. You can find the question at stackoverflow, too.
I want to start with a first look how the solution should look like. The following picture shows the described layout on a big and on a small screen:
Let’s discuss several approaches that we can use to create this behavior.
Switch between HBox and VBox
One suggested solution is to switch between a HBox and a VBox at runtime. This means that on a big screen you will see the image and text wrapped in a HBox and when the size becomes smaller the HBox will be replaced by a VBox. By doing so we need to discuss if we want to reuse the text and image component in both layouts or create separate instance for each layout. Here I think that a recycling of the components is a good idea. If you use 2 instance you need to sync them. By using the JavaFX property API this isn’t as hard as it sounds in the first moment but it can still create some errors. So let’s have a look at a code snippet that creates the basic view:
In this example the text will be displayed under the image as it should look on small devices:
As a last step we want to modify the code and create an application that will change it’s layout dynamically:
In this first try the mainPane contains the hBox or the vBox depending on the width of the scene. To do so a lister is attached to the width property. In addition the children of the vBox and hBox will be cleared and the text and image will be attached to the currently visible panel. As you can see in this video the view already behaves like it should:
There are still some ugly parts in the code. As you might have noticed the listener will be called for each repaint of our stage. therefore nodes will be replaced and added to the scene graph all the time. Here we can use the JavaFX binding API to create a more performant binding. Here is the code snippet that shows the changed code:
Now the scene graph will only be changed if the size will become greater or smaller than 600 pixel.
I think this is a valid solution for the given problem and we can create a responsive behavior this way. But I think that it’s not the perfect solution and therefore I will show another and easier approach the next days.