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 e Column questa proprietà è già fissata all’asse appropriato, ossia orizzontale per Row e verticale per 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 e end nella direzione orizzontale |
verticalDirection |
VerticalDirection |
fornisce la disposizione dei widget figli verticalmente e definisce come interpretare lo start e end nella direzione verticale |
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
che Column
abbiamo definito due Text
che si dispongono in ordine lungo gli assi orizzontali e verticali, rispettivamente. In particolare, per rendere evidente l’effetto riga e colonna, abbiamo inserito i suddetti widget in appositi container di cui è stato definito il colore.
Eseguendo l’app otteniamo il risultato in figura.
![Definizione dei widget Row e Column all’interno di appositi Container](https://static.html.it/app/uploads/2019/07/fig98.png)
Passiamo adesso all’esplorazione della proprietà mainAxisAlignment
.
Definiamo all’interno del nostro StatelessWidget
un nuovo metodo che tornerà un oggetto di tipo Widget
e che prende in ingresso il valore desiderato per 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
composto da un background colorato e avente come figlio un widget Row
che presenta:
- la proprietà
mainAxisAlignment
impostata al valore passato per parametro; - 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.
![Utilizzo della proprietà mainAxisAlignment usando i valori start e center per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig99.png)
In questo caso, gli elementi verranno spostati all’inizio o al centro della riga. Utilizzando le altre proprietà offerte da MainAxisAlignment
otterremo il seguente risultato.
![Diversi esempi di utilizzo della proprietà mainAxisAlignment per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig100.png)
In particolare, è interessante porre l’attenzione sulle proprietà spaceBetween
, spaceEvenly
, e spaceAround
che aggiungono uno spazio tra i widget figli della Row
in modo differente, come si è potuto notare.
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
, scrivendo un metodo analogo (disponibile su GitHub).
Pertanto utilizzando le proprietà start
, center
ed end
otterremo il seguente risultato.
![Utilizzo della proprietà mainAxisAlignment con il widget Column per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig101.png)
Vediamo ora la proprietà crossAxisAlignment
.
Come si è potuto notare, la proprietà mainAxisAlignment
lavora orizzontalmente per le Row
e verticalmente per le Column
. La proprietà crossAxisAlignment
è invece perpendicolare alla prima e quindi agirà verticalmente sulle Row
e orizzontalmente sulle Column
.
Vediamo un esempio di utilizzo tramite il widget Row
. Definiamo un metodo che restituisca un nuovo widget Row
composto da quattro widget Text
e avente la proprietà crossAxisAlignment
impostata al valore passato da parametro.
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
quali start
, center
ed end
per ottenere il seguente risultato.
![Utilizzo della proprietà crossAxisAlignment con il widget Row per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig103.png)
Come si può notare i quattro widget Text
sono stati disposti in alto, al centro e in basso all’interno del container.
Analogamente, possiamo ripetere lo stesso esperimento con il widget Column
scrivendo un metodo analogo e disponibile al seguente link.
Pertanto utilizzando le proprietà start
, center
ed end
otterremo il seguente risultato.
![Utilizzo della proprietà crossAxisAlignment con il widget Column per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig104.png)
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
, in quanto per il widget Column
il comportamento sarà il medesimo ma sull’asse verticale.
Come già fatto in precedenza, definiamo un nuovo metodo che ritorna un Widget
e prende come parametro di ingresso un valore per 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
come figli della Row
e imposta il mainAxisSize
al valore passato per parametro.
Invocando perciò il metodo con i valori di min
e max
, otterremo quanto segue.
![Utilizzo della proprietà mainAxisSize per il widget Row per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig105.png)
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. In questa sede, ci limiteremo a mostrare un semplice esempio di utilizzo con Column
.
Definiamo un nuovo metodo che ha come scopo quello di creare un widget Column
e di impostare la verticalDirection
passata da parametro.
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
e up
di VerticalDirection
ottenendo il risultato in figura.
![Utilizzo della proprietà verticalDirection con un widget Column per a) Android e b) iOS](https://static.html.it/app/uploads/2019/07/fig106.png)
In questo caso, con la proprietà down
gli elementi vengono disposti dall’alto verso il basso, mentre con la proprietà up
sono disposti dal basso verso l’alto.
Il codice di questa lezione è disponibile su GitHub.