Using Containers
Anchors are an efficient way to handle different aspect ratios for basic multiple resolution handling in GUIs.
Per le interfacce utente più complesse, potrebbero diventare difficile da utilizzare.
Questo è spesso il caso di giochi come gli RPG, le chat online, i tycoon o le simulazioni. Un altro caso comune in cui potrebbero essere necessarie funzionalità più avanzate di layout sono strumenti di gioco (o semplicemente strumenti).
Tutte queste situazioni richiedono un'interfaccia utente più funzionale, simile a quella di un sistema operativo, con layout e formattazione avanzati. Per questo, i Container sono più utili.
Container layout
Containers provide a huge amount of layout power (as an example, the Godot editor user interface is entirely done using them):
Quando si usa un nodo derivato da Container, tutti i nodi Control figlio rinunciano alla propria capacità di posizionamento. Ciò significa che il Container controllerà il loro posizionamento e qualsiasi tentativo di modifica manuale di questi nodi verrà ignorato o invalidato la prossima volta che il nodo padre viene ridimensionato.
Allo stesso modo, quando un nodo derivato da un Container viene ridimensionato, tutti i suoi figli verranno riposizionati di conseguenza, con un comportamento basato sul tipo di contenitore utilizzato:
Esempio di HBoxContainer ridimensionante i pulsanti figlio.
Il vero potenziale dei contenitori è che si possono annidare (come nodi), consentendo la creazione di layout molto complessi che si ridimensionano senza sforzo.
Opzioni di dimensionamento
When adding a node to a container, the way the container treats each child depends mainly on their container sizing options. These options can be found by inspecting the layout of any Control that is a child of a Container.
Le opzioni di dimensionamento sono indipendenti per il dimensionamento verticale e orizzontale e non tutti i contenitori le utilizzano (ma quasi tutti sì):
Fill: Ensures the control fills the designated area within the container. No matter if a control expands or not (see below), it will only fill the designated area when this is toggled on (it is by default).
Expand: Attempts to use as much space as possible in the parent container (in each axis). Controls that don't expand will be pushed away by those that do. Between expanding controls, the amount of space they take from each other is determined by the Stretch Ratio (see below). This option is only available when the parent Container is of the right type, for example the HBoxContainer has this option for horizontal sizing.
Shrink Begin When expanding, try to remain at the left or top of the expanded area.
Shrink Center When expanding, try to remain at the center of the expanded area.
Shrink End When expanding, try to remain at the right or bottom of the expanded area.
Stretch Ratio: The ratio of how much expanded controls take up the available space in relation to each other. A control with "2", will take up twice as much available space as one with "1".
Experimenting with these flags and different containers is recommended to get a better grasp on how they work.
Container types
Godot provides several container types out of the box as they serve different purposes:
Box Containers
Arranges child controls vertically or horizontally (via HBoxContainer and VBoxContainer). In the opposite of the designated direction (as in, vertical for a horizontal container), it just expands the children.
These containers make use of the Stretch Ratio property for children with the Expand flag set.
Grid Container
Arranges child controls in a grid layout (via GridContainer, amount of columns must be specified). Uses both the vertical and horizontal expand flags.
Margin Container
Child controls are expanded towards the bounds of this control (via MarginContainer). Padding will be added on the margins depending on the theme configuration.
Again, keep in mind that the margins are a Theme value, so they need to be edited from the constants overrides section of each control:
Contenitore di schede
Consente di posizionare più controlli figlio uno sopra l'altro (tramite TabContainer), lasciando visibile solo quello attuale.
Il cambio di quello attuale si fa tramite le schede poste in alto al contenitore, cliccandoci:
I titoli sono generati normalmente dai nomi dei nodi (sebbene si possano sovrascrivere tramite l'API del TabContainer).
È possibile modificare impostazioni quali il posizionamento delle schede e lo StyleBox nelle sostituzioni del tema del TabContainer.
Split Container
Accetta solo uno o due controlli figlio, poi li colloca uno accanto all'altro con un divisore (tramite HSplitContainer e VSplitContainer). Rispetta sia i flag orizzontali sia i flag verticali, così come il Ratio.
Il divisore si può trascinare per cambiare la relazione dimensionale tra entrambi i figli:
PanelContainer
Un contenitore che disegna uno StyleBox, poi espande i figli per coprire la sua intera area (tramite PanelContainer, rispettando i margini dello StyleBox). Rispetta sia le opzioni di dimensionamento orizzontale sia verticale.
Questo contenitore è utile come controllo di primo livello, o semplicemente per aggiungere sfondi personalizzati alle sezioni di un layout.
FoldableContainer
A container that can be expanded/collapsed (via FoldableContainer). Child controls are hidden when it is collapsed.
ScrollContainer
Accetta un singolo nodo figlio. Se questo nodo è più grande del contenitore, saranno aggiunte barre di scorrimento per spostare il nodo all'interno (tramite ScrollContainer). Sono rispettate entrambe le opzioni di dimensione verticale e orizzontale e il comportamento si può attivare o disattivare per ogni asse nelle proprietà.
Anche la rotellina del mouse e il trascinamento tattile (quando il tocco è disponibile) sono metodi validi per spostare il controllo figlio.
Come nell'esempio precedente, uno dei modi più comuni per utilizzare questo contenitore è insieme a un VBoxContainer come figlio.
AspectRatioContainer
Un tipo di contenitore che dispone i suoi controlli figlio in modo da mantenerne automaticamente le proporzioni quando il contenitore viene ridimensionato (tramite AspectRatioContainer). Ha diverse modalità di stiramento, che forniscono opzioni per regolare le dimensioni dei controlli figlio in base al contenitore: "riempi" (fill), "larghezza controlla altezza" (width control height), "larghezza controlla altezza" (height control width) e "copri" (cover).
Utile quando c'è bisogno di un contenitore che deve essere dinamico e reattivo alle diverse dimensioni dello schermo e si desidera che gli elementi figlio siano ridimensionati proporzionalmente senza perdere le loro forme previste.
FlowContainer
FlowContainer è un contenitore che dispone i suoi controlli figlio orizzontalmente o verticalmente (tramite HFlowContainer e tramite VFlowContainer). Quando lo spazio disponibile si esaurisce, sposta i figli nella riga o colonna successiva, in modo simile a come il testo va a capo in un libro.
Utile per creare layout flessibili in cui i controlli figlio si adattano automaticamente allo spazio disponibile senza sovrapporsi.
CenterContainer
CenterContainer è un contenitore che mantiene automaticamente tutti i suoi controlli figlio centrati al suo interno, alle loro dimensioni minime. Garantisce che i controlli figlio siano sempre allineati al centro, semplificando la creazione di layout centrati senza posizionamento manuale (tramite CenterContainer).
SubViewportContainer
Questo è un controllo speciale che accetterà solo un singolo nodo Viewport come figlio e lo visualizzerà come se fosse un'immagine (tramite SubViewportContainer).
Creare contenitori personalizzati
È possibile creare un contenitore personalizzato tramite script. Ecco un esempio di contenitore che adatta i nodi figlio alle sue dimensioni:
extends Container
func _notification(what):
if what == NOTIFICATION_SORT_CHILDREN:
# Must re-sort the children
for c in get_children():
# Fit to own size
fit_child_in_rect(c, Rect2(Vector2(), size))
func set_some_setting():
# Some setting changed, ask for children re-sort.
queue_sort()
using Godot;
public partial class CustomContainer : Container
{
public override void _Notification(int what)
{
if (what == NotificationSortChildren)
{
// Must re-sort the children
foreach (Control c in GetChildren())
{
// Fit to own size
FitChildInRect(c, new Rect2(new Vector2(), Size));
}
}
}
public void SetSomeSetting()
{
// Some setting changed, ask for children re-sort.
QueueSort();
}
}