devstory

Le Tutoriel de Flutter Row

View more Tutorials:

1- Flutter Row

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
    }
)

2- children

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:(){}),
    ]
)

3- Add/Remove children

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:
  1. 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.
  2. 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();
          }
      ),
    );
  }
}

4- mainAxisAlignment

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

5- mainAxisSize

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

 

6- crossAxisAlignment

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

7- textDirection

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".

8- verticalDirection

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".

9- textBaseline

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

View more Tutorials: