Compreso il funzionamento di Flutter e dei suoi componenti base, iniziamo a compiere i primi passi per la creazione di layout più articolati per suddividere lo spazio della schermata in righe o colonne e per sovrapporre tra loro due widget.
In questa lezione vedremo nel dettaglio i widget Row
e Column
offerti da Flutter per la creazione di Multi-Child layout.
Row e Column Widget
Uno dei principali task nello sviluppo di un’app è quello di collocare correttamente gli elementi all’interno della schermata. Questo processo può avvenire in diversi modi, come ad esempio organizzare la schermata in righe e/o in colonne per disporre in modo appropriato gli elementi che contiene.
Per fare ciò, Flutter dispone dei widget Row
e Cloumn
, che risultano tra loro complementari e permettono l’organizzazione dei widget figli rispettivamente in righe e colonne. Nessuno dei due widget permette lo scroll orizzontale o verticale e qualora fosse necessario visualizzare un numero elevato di elementi è consigliabile usare una ListView
.
Nel caso in cui non fosse noto a priori se usare una Row
o una Column
per la visualizzazione dei dati, Flutter mette a disposizione il widget Flex
, che permette di controllare su quale asse (orizzontale o verticale) andare a disporre i figli. È consigliabile però sapere sempre come visualizzare i dati, in quanto l'uso di Flex
può risultare eccessivamente verboso.
Infine, nel caso ci sia un solo elemento da visualizzare, invece di usare Flex
, Row
o Column
è consigliabile utilizzare i widget Align
o Center
per posizionarlo nella schermata.
Le proprietà
A differenza degli altri widget definiti finora, composti da proprietà eterogenee, i widget Row
e Column
definiscono il medesimo set di proprietà, in quanto il primo è semplicemente una variante del secondo e viceversa. Tra le principali proprietà che è fondamentale conoscere ritroviamo:
Proprietà | Tipo Accettato | Descrizione |
---|---|---|
children
|
List<Widget>
|
è la lista di widget contenuti all’interno di questo componente e sottoalbero |
crossAxisAlignment
|
CrossAxisAlignment
|
rappresenta come devono essere i widget figli posizionati lungo gli assi attraverso l’utilizzo delle proprietà offerte dal widget CrossAxisAlignment
|
direction
|
Axis
|
la direzione da utilizzare per l’asse principale. Per Row
Column
Row
Column
|
mainAxisAlignment
|
MainAxisAlignment
|
definisce come posizionare i widget figli attorno all’asse principale |
mainAxisSize
|
MainAxisSize
|
rappresenta quanto spazio deve essere occupato nell’asse principale |
textDirection
|
TextDirection
|
determina la disposizione dei widget figli orizzontalmente e come interpretare lo start
end
|
verticalDirection
|
VerticalDirection
|
fornisce la disposizione dei widget figli verticalmente e definisce come interpretare lo start
end
|
Comprese le proprietà di questi due widget simili tra loro, vediamo qualche esempio pratico.
Esempi pratici
Per iniziare, creiamo un nuovo progetto come mostrato nella lezione 6 di questa guida e, lasciando inalterati gli import, il metodo main()
e la classe MyApp
, cancelliamo il resto per aggiungere il seguente StatelessWidget
composto da uno Scaffold
per la definizione dell’AppBar
e da una SingleChildScrollView
(di cui abbiamo già parlato nella lezione 11), che conterrà tutti i nostri esempi pratici di import delle immagini.
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Lesson 16'),
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
//we will add our widgets here.
],
)),
);
}
}
Modifichiamo infine la classe MyApp
per impostare il widget appena creato come home.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// . . .
home: MyPage(),
);
}
}
Ora siamo pronti per le nostre sperimentazioni.
Partiamo subito da un semplice utilizzo di questi due widget.
Container(
color: Colors.orange[100],
child: Row(children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
)
])),
// . . .
Container(
color: Colors.orange[100],
child: Column(children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
)
])),
In questo caso, sia per il widget Row
Column
Text
Eseguendo l’app otteniamo il risultato in figura.

Passiamo adesso all’esplorazione della proprietà mainAxisAlignment
Definiamo all’interno del nostro StatelessWidget
Widget
mainAxisAlignment
Widget _rowMainAlign(mainAxisAlignment) => Container(
color: Colors.lightBlue[50],
child: Row(
mainAxisAlignment: mainAxisAlignment,
children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text3",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text4",
style: TextStyle(color: Colors.black, fontSize: 17),
),
],
),
height: 30,
margin: EdgeInsets.all(5),
);
In particolare, in questo metodo abbiamo definito un Container
Row
- la proprietà
mainAxisAlignment
- un lista di widget
Text
In questo modo, richiamando il metodo con le diverse proprietà fornite dal widget MainAxisAlignment
potremo vedere il diverso comportamento di questa proprietà.
Ad esempio, impostando passando come parametro le proprietà MainAxisAlignment.start
e MainAxisAlignment.center
otteremo quanto segue.

In questo caso, gli elementi verranno spostati all’inizio o al centro della riga. Utilizzando le altre proprietà offerte da MainAxisAlignment

In particolare, è interessante porre l’attenzione sulle proprietà spaceBetween
spaceEvenly
spaceAround
Row
Prorpietà | Descrizione |
---|---|
spaceBetween
|
aggiunge uno spazio tra i widget figli spingendo il primo e l’ultimo elemento agli estremi |
spaceEvenly
|
aggiunge uno spazio prima e dopo i widget figli affinché esso sia uguale per tutti |
spaceAround
|
aggiunge uno spazio attorno ai widget che si somma nel caso di due widget vicini tra loro, aumentando la distanza |
Similmente, possiamo ripetere lo stesso esperimento con il widget Column
GitHub
Pertanto utilizzando le proprietà start
center
end

Vediamo ora la proprietà crossAxisAlignment
Come si è potuto notare, la proprietà mainAxisAlignment
Row
Column
crossAxisAlignment
Row
Column
Vediamo un esempio di utilizzo tramite il widget Row
Row
Text
crossAxisAlignment
Widget _rowCrossAxisAlignment(crossAxisAlignment) => Container(
color: Colors.lightGreen[50],
child: Row(
crossAxisAlignment: crossAxisAlignment,
children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text3",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text4",
style: TextStyle(color: Colors.black, fontSize: 17),
),
],
),
height: 50,
margin: EdgeInsets.all(5),
);
Invochiamo quindi il metodo appena scritto passando come parametro le proprietà di CrossAxisAlignment
start
center
end

Come si può notare i quattro widget Text
Analogamente, possiamo ripetere lo stesso esperimento con il widget Column
link
Pertanto utilizzando le proprietà start
center
end

Esaminiamo, adesso, la proprietà mainAxisAlignment
Essa permette di definire la dimensione dell’asse principale di entrambi i widget. In particolare, possiamo assegnare a questa proprietà due valori:
Valore | Descrizione |
---|---|
MainAxisAlignment.min
|
assegna la minima dimensione possibile al widget, che sarà grande quanto la somma totale delle dimensioni dei suoi widget figli |
MainAxisAlignment.max
|
assegna la massima dimensione possibile al widget |
Vediamo un semplice esempio con il widget Row
Column
Come già fatto in precedenza, definiamo un nuovo metodo che ritorna un Widget
mainAxisSize
Widget _rowMainAxisSize(mainAxisSize) => Container(
color: mainAxisSize == MainAxisSize.min ? Colors.pink : Colors.yellowAccent,
child: Row(
mainAxisSize: mainAxisSize,
children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text3",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text4",
style: TextStyle(color: Colors.black, fontSize: 17),
),
],
));
In particolare, questo metodo definisce quattro widget Text
Row
mainAxisSize
Invocando perciò il metodo con i valori di min
max

Chiudiamo infine questa sezione di esempi con l’utilizzo della proprietà verticalDirection
Il comportamento cambia in base a quale widget usiamo e a quali proprietà sono definite. Per ulteriori dettagli rimandiamo alla documentazione ufficiale
Column
Definiamo un nuovo metodo che ha come scopo quello di creare un widget Column
verticalDirection
Widget _columnVerticalDirection(verticalDirection) => Container(
color: Colors.lightBlue[50],
child: Column(
verticalDirection: verticalDirection,
children: <Widget>[
Text(
"Text1",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text2",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text3",
style: TextStyle(color: Colors.black, fontSize: 17),
),
Text(
"Text4",
style: TextStyle(color: Colors.black, fontSize: 17),
),
],
),
height: 150,
margin: EdgeInsets.all(5),
);
Invochiamo ora il metodo passando come parametro il valore down
up
VerticalDirection

In questo caso, con la proprietà down
up
Il codice di questa lezione è disponibile su GitHub