Flow container for Godot 3.5 or newer
Godot 3.5 (currently in beta) introduces HFlowContainer
and VFlowContainer
that will serve the propuse described.
The HFlowContainer
will fill a row and when they overflow, it will add a new row and continue there. The VFlowContainer
will work on a similar fashion but with columns.
Flow containers before Godot 3.5
For older versions of Godot you can use the HFlowContainer
addon which you can find it in the asset library (here). Note that there is no VFlowContainer
counterpart.
As everything on the asset library it is free and open source, so feel free to read the code and modify it, which can be serve as starting point if you want to make your own custom Container
.
Making your own custom Container
The gist of making a custom Container
is that it must position its children.
For that effect you react to NOTIFICATION_SORT_CHILDREN
in the _notification
method. You might also want to react to NOTIFICATION_RESIZED
.
You can have a method - which I'll call layout
- that you call when you get the notifications:
func _notification(what):
if what == NOTIFICATION_SORT_CHILDREN:
layout()
And also call layout
from the setters (setget
) of the properties that define how the Container
must organize its children. To call layout
from anywhere other than _notification
, you might want to use call_deferred("layout")
to prevent any possible re-layout loops from hanging or crashing the game.
The layout
method would iterate over the visible children Control
s and use get_combined_minimum_size
to figure out their size.
Something like this:
func layout() -> void:
# …
for child in get_children():
var control := child as Control
if not is_instance_valid(control) or not control.visible:
continue
var size := control.get_combined_minimum_size()
# …
Then using that information compute the position and size for the children Control
s. When there is room for the Control
s to grow, you may want to split it among them according to their size_flags_stretch_ratio
.
Once you have the position and size for a Control
decided, use fit_child_in_rect
to position them, which will take into account grow and size flags.
Thus - barring the simplest Container
s - you will need to iterate over the children Control
s twice. And for that you might find useful to have an auxiliary data structure to temporarily store them.