Amazon.co.uk Widgets

This is the seventh part of a journey to build and publish a Flutter™ based app using Material Components for Flutter (MDC-Flutter).

Adding all the Material Components widgets to our app page

Adding all the MDC-Flutter widgets to the app is a giid way to learn about them. We have already build an AppbarMaterialAppScaffoldButtonBar, and, FlatButton, (which is inside the Card. There are a lot more.

In this article lets add:

  • Buttons
  • Floating Action Button
  • Chips
  • Data table
  • Dialogs
  • List View
  • Popup Menu
  • Navigation Drawer

Buttons

There are three main types of button to think about for our MDC-Flutter app. "Text Button", "Elevated Button" and "Outlined Button".

This is a text label displayed on a widget in a theme colour that reacts to taps by change of color.
This has a colour from the theme and increases elevation when tapped.
This is a button with a thin border.

Flutter 1.22.0 added a group of changes affecting buttons - "New Button Universe #59702" which make them far easier to understand and theme effectively, especially for people like me who are relatively new to Flutter.


// This shows new names for buttons released in Flutter 1.22.0 (See Issue #61262)
TextButton(
  onPressed: onPressed ?? () { },
  child: Text('TEXT'),
),
ElevatedButton(
  onPressed: onPressed ?? () { },
  child: Text('CONTAINED'),
),  
OutlinedButton(
  onPressed: onPressed ?? () { },
  child: Text('OUTLINED'),   
), 

The buttons pick up the underlying theme colours and auto adjust for dark appearance.

Flutter Material Components Android light appearance - New Button Universe   Flutter Material Components Android light appearance - New Button Universe

Floating action Button

A floating action button (FAB) represents the primary action of a screen. This is an extended one with text and an icon. The onPressed method doesnt do anything yet. The colour is themed. It uses the accentColor, so it needs to be set for theme and for dark theme. Not sure where or how it decides to style the text but it looks OK.


theme: ThemeData(
  accentColor: lightwhichisdarker[200], // Accent colour is also known as the secondary colour.
...
darkTheme: ThemeData(
  accentColor: darkwhichislighter[200], // Accent colour is also known as the secondary colour.
...
floatingActionButton: FloatingActionButton.extended(
  onPressed: () {
  // TBD
  },
  label: Text('SHARE'),
  icon: Icon(Icons.share),
),

Flutter Material Components Android light appearance Extended Floating Action Bar   Flutter Material Components Android dark appearance Extended Floating Action Bar

Chips

Chips are compact elements that represent an attribute, text, entity, or action. There are several chip types. they are pretty useful and once you look at them in Flutter you keep noticing them in apps!


ExpansionTile(
  leading: Icon(Icons.folder_special),
  title: Text('Chips'),
  subtitle: Text('Chip, CircleAvatar, InputChip, ChoiceChip, FilterChip, ActionChip'),
  children: [
     Chip(
       avatar: CircleAvatar(
         child: Text('C'),
       ),
       label: Text('Chip'),
     ),
     InputChip(
       avatar: CircleAvatar(
         child: Text('IC'),
       ),
       label: Text('Input Chip'),
       onPressed: () {
         print('Input Chip pressed.');
       }
      ),
      ChoiceChip(
        label: const Text('Choice Selected'),
        selected: true,
        onSelected: (bool selected) { },
      ),
      ChoiceChip(
        label: const Text('Choice'),
        selected: false,
        onSelected: (bool selected) { },
      ),
      ChoiceChip(
        label: const Text('Choice Disabled'),
        selected: false,
      ),
      FilterChip(
        label: const Text('Filter Selected'),
        selected: true,
        onSelected: (bool selected) { },
      ),
      FilterChip(
        label: const Text('Filter'),
        selected: false,
        onSelected: (bool selected) { },
      ),
      ActionChip(
        label: const Text('Action Chip'),
          onPressed: () {
            print('Action Chip pressed.');
          }
     ),
  ],
),

Chip, InputChip, ChoiceChip, FilterChip, and ActionChip.

Flutter Material Components Android light appearance - Chips   Flutter Material Components Android dark appearance - Chips

Data table

Data tables display sets of data across rows and columns. The documentation warns that they are expensive (meaning that they require resources for computation) because they need to measure and negotiate dimensions for columns. It is a benefit to have the platform do this rather than try to write such code! Flutter also has PaginatedData Table to reduce this demand by splitting data into multiple pages.

The data table component does not seem to be easy to style. Here is its code block and light appearance look on Android and iOS.


ExpansionTile(
  leading: Icon(Icons.table_chart),
  title: Text('Data Tables'),
  subtitle: Text('textTheme'),
  children: [
    DataTable(
      columns: const [
        DataColumn(
          label: Text(
            'Shape',
            style: TextStyle(color: parchmentLightOnSurface),
          ),
        ),
        DataColumn(
          label: Text(
            'Points',
            style: TextStyle(color: parchmentLightOnSurface),
          ),
        ),
        DataColumn(
          label: Text(
            'Like',
            style: TextStyle(color: parchmentLightOnSurface),
          ),
        ),
      ],
      rows: const [
        DataRow(
          cells: [
            DataCell(Text('Triangle')),
            DataCell(Text('3')),
            DataCell(Text('No')),
          ],
        ),
        DataRow(
          cells: [
            DataCell(Text('Square')),
            DataCell(Text('4')),
            DataCell(Text('No')),
          ],
        ),
        DataRow(
          cells: [
            DataCell(Text('Octagon')),
            DataCell(Text('8')),
            DataCell(Text('Yes')),
          ],
        ),
      ],
    ),
  ],
),

DataTable, DataColumn, DataRow, DataCell

Flutter Material Components iOS Data table   Flutter Material Components Android Data table

You can see that the header row is styled, and the DataCell is not. Sadly neither appear in Dark appearance. This will be revisited.

Dialogs

There are a couple of dialog types available; AlertDialog, for dialogs that have a message and one or more buttons and SimpleDialog, for dialogs that offer one or more options.


ExpansionTile(
    leading: Icon(Icons.error),
    title: Text('Dialogs'),
    subtitle: Text('AlertDialog, SimpleDialog'),
    children: [
      AlertDialog(
        title: new Text("AlertDialog"),
        content: new Text("AlertDialog content"),
        actions: [
          new FlatButton(
            child: new Text("Close"),
            onPressed: () {
              print('Close button pressed.');
            },
          ),
        ],
      ),
      SimpleDialog(
        title: const Text('SimpleDialog'),
        children: [
          SimpleDialogOption(
            onPressed: () {
              print('Item 1 pressed.');
            },
            child: const Text('Item 1'),
          ),
          SimpleDialogOption(
            onPressed: () {
              print('Item 2 pressed.');
            },
            child: const Text('Item 2'),
          )
        ],
      )
    ]),

AlertDialog, SimpleDialog

Flutter Material Components iOS Dialogs table   Flutter Material Components Android Dialogs

List View

Adding a ListView to our ExpansionTile required settingshrinkWrap and AxisDirection. Othereise this is just the ListView example with dividers from the Flutter documentation


// Values for the ListView
final List entries = ['A', 'B', 'C'];
final List colorCodes = [600, 500, 100];

// ListView Expansion Tile
ExpansionTile(
  leading: Icon(Icons.list),
  title: Text('ListView'),
  subtitle: Text('Listview with dividers'),
  children: [
    ListView.separated(
      scrollDirection: Axis.vertical,
      shrinkWrap: true,
      itemCount: entries.length,
      itemBuilder: (BuildContext context, int index) {
        return Container(
          height: 50,
          color: Colors.amber[colorCodes[index]],
          child: Center(child: Text('Entry ${entries[index]}')),
        );
      },
      separatorBuilder: (BuildContext context, int index) =>
          const Divider(),
    ),
  ],
),

Flutter Material Components ListView   Flutter Material Components ListView

Popup Menu

It is easy to add a popup menu to the App Bar actions Widget attached to a Vertical More Icon.


PopupMenuButton(
  icon: Icon(Icons.more_vert),
  itemBuilder: (context) => [
    PopupMenuItem(
    child: Text("Settings"),
    ),
    PopupMenuItem(
    child: Text("Help and Contact Us"),
    ),
    PopupMenuItem(
    child: Text("About nameofyourproject"),
    ),
  ],
),

Flutter Material Components PopupMenu   Flutter Material Components PopupMenu

Adding a Navigation Drawer

Navigation drawers are commonplace now, and the Menu icon is well understood as a visual cue that there is a menu lurking behind it. Adding a Menu icon is automatic when you use the navigation drawer in Flutter, but since we had a leading icon it has to go. That is a shame but there is probably a better place for the branding. Comment out the leading: Image.asset('assets/ezone-24-white.png'), line and add the drawer and sav and magically the drawer Menu appears. Once again, Flutter saves days and days of work and testing.

Flutter Material Components Hamburger Menu   Flutter Material Components Hamburger Menu

Our Navigation Drawer is pretty simple. It contains a ListView which contains a DrawerHeader which contains the text for the app title. The text style inherits the theme and therefore works in dark and light appearance, as does the DrawerHeader through decoration.

Each ListTile contains a leading icon, (which isnt yet themed), some text, and optionally a trailing Icon or text. The Icon(Icons.keyboard_arrow_right) is often used to denote a that there is a further page to be found. The number migth represent unread items for example.


// Navigation Drawer
drawer: Drawer(
    child: ListView(
        children: [
          DrawerHeader(
            child:
            Text("Your Project", style: Theme.of(context).textTheme.headline3),
            decoration: BoxDecoration(
              color: Theme.of(context).primaryColor,
            ),
          ),
          ListTile(
            leading: Icon(Icons.star_border),
            title: Text('Outline Star', style: Theme.of(context).textTheme.headline6),
            trailing: Icon(Icons.keyboard_arrow_right),
          ),
          ListTile(
            leading: Icon(Icons.star_half),
            title: Text('Half Star', style: Theme.of(context).textTheme.headline6),
            trailing: Text('39', style: Theme.of(context).textTheme.subtitle2),
          ),
          ListTile(
            leading: Icon(Icons.star),
            title: Text('Star', style: Theme.of(context).textTheme.headline6),
            trailing: Icon(Icons.keyboard_arrow_right),
          ),
        ]
    )
),

It is still a little bare, we will revisit it to add some branding and make it more interesting.

Flutter Material Components Navigation Drawer   Flutter Material Components Navigation Drawer

In the next article lets add the other components. Then we can move on with a view to making our app real rather than a non functional demonstration swiss army knife type app.