Le Tutoriel de Flutter Row
View more Tutorials:
Row est un widget qui affiche ses widgets enfants sur une ligne. Une autre variante est Column qui montre ses widgets enfants sur une colonne.
Pour que le widget enfant de Row s'ouvre pour remplir l'espace horizontal disponible, vous pouvez l'envelopper dans un objet Expanded.
Row place ses enfants sur une ligne et ne peut pas se défiler. Si vous souhaitez obtenir un conteneur similaire et défilable, vous pouvez utiliser ListView.
Row Constructor:
Row Constructor
Row( {Key key, List<Widget> children: const <Widget>[], MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, MainAxisSize mainAxisSize: MainAxisSize.max, CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, TextBaseline textBaseline: TextBaseline.alphabetic } )
La propriété children est utilisée pour définir une liste des widgets enfants de Row.
Vous pouvez ajouter des widgets enfants à children ou supprimer des widgets de children, mais vous devez suivre la règle mentionnée dans la section "Add/Remove Children".
List<Widget> children: const <Widget>[]
À commencer par le premier exemple, une Row avec quatre widgets enfants:

main.dart (children ex1)
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'o7planning.org', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: MyHomePage(), ); } } class MyHomePage extends StatelessWidget { MyHomePage({Key key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Flutter Row Example") ), body: Center( child: Row ( children: [ ElevatedButton(child: Text("BTN 1"), onPressed:(){}), Icon(Icons.ac_unit, size: 64, color: Colors.blue), ElevatedButton( child: Text("Button 2"), onPressed:(){}, style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size.square(100)) ) ), ElevatedButton(child: Text("BTN 3"), onPressed:(){}), ] ) ), ); } }
Certains widgets enfants avec flex> 0 sont capables d'étendre sa largeur pour remplir l'espace restant horizontalement comme Expanded et Spacer, etc. Ils sont souvent utilisés pour ajuster la distance entre les widgets enfants de Row. Ci-dessous un exemple:

children (ex2)
Row ( children: [ ElevatedButton(child: Text("BTN 1"), onPressed:(){}), Expanded( flex: 1, child: Icon(Icons.ac_unit, size: 64, color: Colors.blue), ), ElevatedButton( child: Text("Button 2"), onPressed:(){}, style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size.square(100)) ) ), Spacer( flex: 2 ), ElevatedButton(child: Text("BTN 3"), onPressed:(){}), ] )
Vous pouvez ajouter quelques widgets enfants à une Row ou en supprimer certains de Row. Suivre l'instruction ci-dessous peut conduire à des résultats inattendus:
** Not Working! **
class SomeWidgetState extends State<SomeWidget> { List<Widget> _children; void initState() { _children = []; } void someHandler() { setState(() { _children.add(newWidget); }); } Widget build(BuildContext context) { // Reusing `List<Widget> _children` here is problematic. return Row(children: this._children); } }
Pour résoudre le problème ci-dessus, vous devez respecter les règles suivantes:
- Les widgets enfants doivent se voir explicitement attribuer une valeur Key, ce qui aide Flutter à reconnaître les anciens ou les nouveaux widgets enfants lorsque le nombre de widgets change.
- Un nouvel objet List doit être créé pour Row.children si un certain widget enfant change, ou le nombre de widgets enfants change.
** Worked! **
class SomeWidgetState extends State<SomeWidget> { List<Widget> _children; void initState() { this._children = []; } // Add or remove some children.. void someHandler() { setState(() { // The key here allows Flutter to reuse the underlying render // objects even if the children list is recreated. this._children.add(newWidget(key: ...)); }); } Widget build(BuildContext context) { // Always create a new list of children as a Widget is immutable. var newChildren = List.from(this._children); this._children = newChildren; return Row(children: this._children); } }
Par exemple:

main.dart (children ex3)
import 'package:flutter/material.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'o7planning.org', debugShowCheckedModeBanner: false, theme: ThemeData( primarySwatch: Colors.blue, visualDensity: VisualDensity.adaptivePlatformDensity, ), home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key}) : super(key: key); @override State<StatefulWidget> createState() { return MyHomePageState(); } } class MyHomePageState extends State<MyHomePage> { List<Widget> _children = []; int idx = 0; @override void initState() { super.initState(); this._children = [ ElevatedButton( key: Key(this.idx.toString()), child: Text("Btn " + idx.toString()), onPressed: (){} ) ]; } void addChildHandler() { this.idx++; this.setState(() { var newChild = ElevatedButton( key: Key(this.idx.toString()), child: Text("Btn " + idx.toString()), onPressed: (){} ); this._children.add(newChild); }); } @override Widget build(BuildContext context) { // Create new List object: this._children = this._children == null? [] : List.from(this._children); return Scaffold( appBar: AppBar( title: Text("Flutter Row Example") ), body: Center( child: Row ( children: this._children ) ), floatingActionButton: FloatingActionButton( child: Icon(Icons.add), onPressed: () { this.addChildHandler(); } ), ); } }
La propriété mainAxisAlignment est utilisée pour spécifier la manière dont les widgets enfants seront organisés sur l'axe principal. Quant à Row, l'axe principal est l'axe horizontal principal.
MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start // MainAxisAlignment enum: MainAxisAlignment.start MainAxisAlignment.center MainAxisAlignment.end MainAxisAlignment.spaceBetween MainAxisAlignment.spaceAround MainAxisAlignment.spaceEvenly
MainAxisAlignment.start
Au cas où textDirection = TextDirection.ltr (par défaut) et mainAxisAlignment = MainAxisAlignment.start, les widgets enfants de Row seront placés côte à côte de gauche à droite.

MainAxisAlignment.start
Row ( mainAxisAlignment: MainAxisAlignment.start, children: [ ElevatedButton(child: Text("Button 1"), onPressed:(){}), ElevatedButton( child: Text("Button 2"), onPressed:(){}, style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size.square(100)) ) ), ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}) ] )
MainAxisAlignment.center

mainAxisAlignment: MainAxisAlignment.center
MainAxisAlignment.end
Au cas où textDirection = TextDirection.ltr (par défaut) et mainAxisAlignment = MainAxisAlignment.end, les widgets enfants de Row seront placés côte à côte de droite à gauche.

mainAxisAlignment: MainAxisAlignment.end
MainAxisAlignment.spaceBetween

mainAxisAlignment: MainAxisAlignment.spaceBetween
MainAxisAlignment.spaceEvenly

mainAxisAlignment: MainAxisAlignment.spaceEvenly
MainAxisAlignment.spaceAround

mainAxisAlignment: MainAxisAlignment.spaceAround
La propriété mainAxisSize spécifie la quantité d'espace vertical devant être occupée par Row. Sa valeur par défaut est MainAxisSize.max, ce qui signifie que Row essaie d'occuper le plus d'espace horizontal possible.
S'il y a un widget enfant avec "flex> 0 && fit! = FlexFit.loose", Row essayera de prendre le plus d'espace possible, quelle que soit la valeur de mainAxisSize.
À l'inverse, si mainAxisSize = MainAxisSize.min, Row aura une largeur suffisante pour tous ses widgets enfants.
MainAxisSize mainAxisSize: MainAxisSize.max // MainAxisSize enum: MainAxisSize.max MainAxisSize.min

La propriété crossAxisAlignment est utilisée pour spécifier la manière dont les widgets enfants seront disposés sur l'axe transversal. Quant à Row, l'axe transversal est l'axe vertical.
CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center // CrossAxisAlignment enum: CrossAxisAlignment.start CrossAxisAlignment.end CrossAxisAlignment.center CrossAxisAlignment.baseline CrossAxisAlignment.stretch
CrossAxisAlignment.start
Au cas où verticalDirection = VerticalDirection.down (par défaut) et crossAxisAlignment = CrossAxisAlignment.start, les widgets enfants de Row seront placés près du bord supérieur de Row.

CrossAxisAlignment.start
Row ( crossAxisAlignment: CrossAxisAlignment.start, children: [ ElevatedButton(child: Text("Button 1"), onPressed:(){}), ElevatedButton( child: Text("Button 2"), onPressed:(){}, style: ButtonStyle( minimumSize: MaterialStateProperty.all(Size.square(100)) ) ), ElevatedButton(child: Text("Very Long Button 3"), onPressed:(){}) ] )
CrossAxisAlignment.center (Default).

crossAxisAlignment: CrossAxisAlignment.center
CrossAxisAlignment.end
Au cas où verticalDirection = VerticalDirection.down (par défaut) et crossAxisAlignment = CrossAxisAlignment.end, les widgets enfants de Row seront placés près du bord inférieur de Row.

crossAxisAlignment: CrossAxisAlignment.end
CrossAxisAlignment.stretch

crossAxisAlignment: CrossAxisAlignment.stretch
CrossAxisAlignment.baseline
crossAxisAlignment: CrossAxisAlignment.baseline
Par exemple:

crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic
La propriété textDirection spécifie la manière dont les widgets enfants de Row seront disposés sur l'axe principal (axe horizontal) et celle dont les mots "start" et "end" sont interprétés.
TextDirection textDirection // TextDirection enum: TextDirection.ltr (Left to Right) (Default) TextDirection.rtl (Right to Left)
Si textDirection = TextDirection.ltr (par défaut), le mot "start" correspondra à "left" et le mot "end" correspondra à "right".
En revanche, au cas où textDirection = TextDirection.rtl, le mot "start" correspondra à "right" et le mot "end" correspondra à "left".
La propriété verticalDirection spécifie comment les widgets enfants de Row seront disposés sur l'axe transversal (axe vertical) et comment les mots "start" et "end" sont interprétés.
VerticalDirection verticalDirection: VerticalDirection.down // VerticalDirection enum: VerticalDirection.down (Default) VerticalDirection.up
Au cas où verticalDirection = VerticalDirection.down (par défaut), le mot "start" correspondra à "top" et le mot "end" correspondra à "bottom".
À l'inverse, si verticalDirection = VerticalDirection.up, le mot "start" correspondra à "bottom" et le mot "end" correspondra à "top".
Si vous alignez les widgets enfants en fonction de la ligne de base (baseline), la propriété textBaseline spécifie le type de ligne de base sera utilisé.
TextBaseline textBaseline: TextBaseline.alphabetic // TextBaseline enum: TextBaseline.alphabetic (Default) TextBaseline.ideographic

Par exemple:
crossAxisAlignment: CrossAxisAlignment.baseline, textBaseline: TextBaseline.alphabetic