Le Tutoriel de Flutter BottomAppBar

View more Tutorials:

1- BottomAppBar

Un menu en bas (bottom) est un style traditionnel des applications iOS. Dans Flutter, vous pouvez le faire avec BottomAppBar. En plus, BottomAppBar dispose d'une fonctionnalité très pratique permettant de lui attacher un FloatingActionButton.
BottomAppBar Constructor:
BottomAppBar constructor
const BottomAppBar(
    {Key key,
    Color color,
    double elevation,
    NotchedShape shape,
    Clip clipBehavior: Clip.none,
    double notchMargin: 4.0,
    Widget child}
)
En général, BottomAppBar est placé dans un Scaffold via la propriété AppBar.bottomNavigationBar et elle apparaître en bas d'un Scaffold.

2- child

child est la propriété la plus importante de BottomAppBar. Dans la plupart des cas d'utilisation, c'est une Row, et cet objet Row contient un ou plusieurs sub Widget(s) tels que IconButton, PopupMenuButton, etc.
Widget child
Un exemple d'une BottomAppBar dont les actions sont IconButton(s) et PopupMenuButton(s).
main.dart (child - ex1)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        bottomNavigationBar: BottomAppBar(
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              IconButton(icon: Icon(Icons.home), onPressed: () {},),
              PopupMenuButton(
                icon: Icon(Icons.share),
                itemBuilder: (context) => [
                  PopupMenuItem(
                    value: 1,
                    child: Text("Facebook"),
                  ),
                  PopupMenuItem(
                    value: 2,
                    child: Text("Instagram"),
                  ),
                ],
              ),
              IconButton(icon: Icon(Icons.email), onPressed: () {},),
            ],
          ),
        )
    );
  }
}
Afin d'étendre l'exemple ci-dessus, on attache un FloatingActionButton à droite de la BottomAppBar.
main.dart (child ex2)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        floatingActionButton: FloatingActionButton.extended (
          elevation: 4.0,
          icon: const Icon(Icons.add),
          label: const Text('Add a task'),
          onPressed: () {},
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
        bottomNavigationBar: BottomAppBar(
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              IconButton(icon: Icon(Icons.home), onPressed: () {},),
              PopupMenuButton(
                icon: Icon(Icons.share),
                itemBuilder: (context) => [
                  PopupMenuItem(
                    value: 1,
                    child: Text("Facebook"),
                  ),
                  PopupMenuItem(
                    value: 2,
                    child: Text("Instagram"),
                  ),
                ],
              ),
              IconButton(icon: Icon(Icons.email), onPressed: () {},),
            ],
          ),
        )
    );
  }
}
Par exemple: Une BottomAppBar avec un FloatingActionButton ancré au milieu.
main.dart (child ex3)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () { },
          tooltip: 'Increment',
          child: Icon(Icons.add),
          elevation: 2.0,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        bottomNavigationBar: BottomAppBar(
          child: new Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              IconButton(icon: Icon(Icons.menu), onPressed: () {},),
              IconButton(icon: Icon(Icons.search), onPressed: () {},),
            ],
          ),
        )
    );
  }
}
Exemple: Personnaliser la hauteur de la BottomAppBar:
main.dart (child ex4)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () { },
          tooltip: 'Increment',
          child: Icon(Icons.add),
          elevation: 2.0,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        bottomNavigationBar: BottomAppBar(
          child: Container(
            height: 90.0,
            child: new Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                IconButton(icon: Icon(Icons.menu), onPressed: () {},),
                IconButton(icon: Icon(Icons.settings), onPressed: () {},),
                IconButton(icon: Icon(Icons.search), onPressed: () {},),
              ],
            ),
          )
        )
    );
  }
}

3- shape

La propriété shape est utilisée pour définir la forme de l'encoche (notch) lorsque FloatingActionButton est placé sur une BottomAppBar.
NotchedShape shape
NotchedShape est une classe abstraite (abstract class), qui dispose de deux sous-classes CircularNotchedRectangle et AutomaticNotchedShape.
  • CircularNotchedRectangle permet de créer une encoche (notch) circulaire adaptée aux FloatingActionButton circulaires.
  • AutomaticNotchedShape permet de créer des encoches (notch) personnalisées adaptées aux différentes formes de FloatingActionButton.
Voici une exemple dans lequel CircularNotchedRectangle est utilisé pour créer une encoche (notch) circulaire:
main.dart (shape ex1)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () { },
          tooltip: 'Increment',
          child: Icon(Icons.add),
          elevation: 2.0,
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        bottomNavigationBar: BottomAppBar(
          child: Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              IconButton(icon: Icon(Icons.menu), onPressed: () {},),
              IconButton(icon: Icon(Icons.search), onPressed: () {},),
            ],
          ),
          shape: CircularNotchedRectangle(),
        )
    );
  }
}
Remarque: Ne pas utiliser CircularNotchedRectangle avec un FloatingActionButton dont la forme n'est pas ciculaire, car le résultat est insatisfaisant.
Par exemple: utiliser AutomaticNotchedShape avec un FloatingActionButton rectangulaire:
main.dart (shape ex3)
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Title of Application',
      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("BottomAppBar Example"),
        ),
        body: Center(
            child:  Text(
              'Flutter BottomAppBar Example',
            )
        ),
        floatingActionButton: FloatingActionButton.extended (
          elevation: 4.0,
          icon: const Icon(Icons.add),
          label: const Text('Add a task'),
          onPressed: () {},
        ),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
        bottomNavigationBar: BottomAppBar(
          child: Row(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              IconButton(icon: Icon(Icons.menu), onPressed: () {},),
              IconButton(icon: Icon(Icons.search), onPressed: () {},),
            ],
          ),
          shape: AutomaticNotchedShape(
              RoundedRectangleBorder(),
              StadiumBorder(side: BorderSide())
          ),
        )
    );
  }
}

4- color

La propriété color est utilisée pour spécifier la couleur de la BottomAppBar.
Color color
color (ex1)
BottomAppBar(
  child: Row(
    mainAxisSize: MainAxisSize.max,
    mainAxisAlignment: MainAxisAlignment.spaceBetween,
    children: <Widget>[
      IconButton(icon: Icon(Icons.menu), onPressed: () {},),
      IconButton(icon: Icon(Icons.search), onPressed: () {},),
    ],
  ),
  shape: CircularNotchedRectangle(),
  color: Colors.greenAccent
)

5- clipBehavior

Clip clipBehavior: Clip.none
  • TODO Link!

View more Tutorials: