Amazon.co.uk Widgets

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

Styled text

The dummy text on the home page of the app is themed, it is headline6. Theres a deep dive into text which you can read all about in the Material documentation.

TL:DR Typography is work in progress. The names of the TextTheme TextStyles conform to the 2018 Material guidelines and are understandable than before but the size, weight and spacing are still from the 2014 Material guidelines. Apps can choose to use the 2018 text style by specifying Typography.material2018() as the value for their Theme's typography. This may not matter much for new apps built with Flutter 1.17 or later but looks like a painful technical debt for those migrating older apps. Nevertheless Flutter keeps moving in the right direction and the changes were signposted pretty well.

Material type scale for Flutter, with Flutter style names

The thing to concentrate on at first is making sure your app is consistent in its use of these Text Styles. MDC-Flutter enforces much style, padding, size and such, and it is important to respect that for a pleasing look and feel app. If you make incongruous text changes the app will just look 'wrong' to an untrained eye, which ultimately affects user statisfaction and app reviews.

NAMESIZEWEIGHTSPACING
headline196.0light-1.5
headline260.0light-0.5
headline348.0normal0.0
headline434.0normal0.25
headline524.0normal0.0
headline620.0medium0.15
subtitle116.0normal0.15
subtitle214.0medium0.1
bodytext116.0normal0.5
bodytext214.0normal0.25
BUTTON14.0medium0.75
caption12.0normal0.4
OVERLINE10.0normal1.5

Note: This uses the Roboto font, and is only an approximation in a web browser of what these TestStyles will look like in an app.

Add each text Theme to the main page to see how they look

The scaffold provides APIs for showing drawers, snack bars, and bottom sheets. It already has a background colour and an Appbar. Lets add a ListView. ListView supports a nice expasion tile with a subtitle, a title and a leading icon so lets add those too.

Edit main.dart. Adjust the body to be a simple ListView and repeat the ExpansionTile adjusting it for every textTheme.


body: Padding(
  padding: EdgeInsets.all(16.0),
  child: ListView (
    children: [
      ExpansionTile(
        leading: Icon(Icons.text_fields),
        title: Text('headline1'),
        subtitle: Text('textTheme'),
        children: [
          Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur eget justo non lacus ullamcorper rhoncus. Nulla sagittis erat non tortor feugiat, porta rhoncus ante fringilla. Suspendisse vulputate leo nisi, et sagittis augue luctus sollicitudin. Donec feugiat sed sapien in vehicula. Nunc auctor blandit lorem vel malesuada. Curabitur sit amet mattis urna, sit amet ornare augue. Mauris luctus metus vitae vehicula dictum. Sed posuere turpis sit amet nisi tristique cursus. Etiam eget facilisis lacus. Sed ac nisi ullamcorper, molestie ligula eget, suscipit libero. In blandit a eros ac scelerisque. Nunc imperdiet erat neque, eu fermentum justo faucibus quis.',
          style: Theme.of(context).textTheme.headline1,
          )
        ],
      ),

So how does it look?

Flutter Material Components Android light appearance ListView of all textThemes   Flutter Material Components Android dark appearance ListView of all textThemes

The ListView and its ExpansionTile just work automatically. Now you can see what the textThemes really look like on a device. They are a bit much though being all separate. Lets put them into one expansion tile.


ExpansionTile(
  leading: Icon(Icons.text_fields),
  title: Text('textTheme'),
  subtitle: Text('headline1-6, subtitle1-2, bodytext1-2, button, overline, caption'),
  children: [
    Text('Lorem!',
      style: Theme.of(context).textTheme.headline1,
    ),
    Text('Lorem ipsum',
      style: Theme.of(context).textTheme.headline2,
    ),
    Text('Lorem ipsum',
      style: Theme.of(context).textTheme.headline3,
    ),
    Text('Lorem ipsum dolor sit',
      style: Theme.of(context).textTheme.headline4,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
      style: Theme.of(context).textTheme.headline5,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur',
      style: Theme.of(context).textTheme.headline6,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.subtitle1,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.subtitle2,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.bodyText1,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.bodyText2,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.button,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.overline,
    ),
    Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit.Curabitur eget justo non lacus ullamcorper rhoncus.',
      style: Theme.of(context).textTheme.caption,
    ),
  ],
),

Flutter Material Components Android light appearance ListView of all textThemes   Flutter Material Components Android dark appearance ListView of all textThemes

Add a Card

Cards are a very common component providing a surface elevated above the background containing content and actions.

Note that all the appearance setting is outside this code block, this is just about the cards in their expansion tile.


ExpansionTile(
  leading: Icon(Icons.crop_7_5),
  title: Text('Cards '),
  subtitle: Text('FlatButton, Image'),
  children: [
    Card(
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          const ListTile(
            leading: Icon(Icons.explicit),
            title: Text('Kometenmelodie 2'),
            subtitle: Text('Kraftwerk'),
          ),
          ButtonBar(
            children: [
              FlatButton(
                child: const Text('BUY'),
                onPressed: () {/* ... */},
              ),
              FlatButton(
                child: const Text('LISTEN'),
                onPressed: () {/* ... */},
              ),
            ],
          ),
        ],
        )
      ),
    Card(
      child: Image.asset('assets/ezone-512-transparent.png',
        fit: BoxFit.fill,
      ),
    ),
  ],

According to the ThemeData documentation, material drop shadows can be difficult to see in a dark theme, so the elevation of a surface should be portrayed with an "overlay" in addition to the shadow. The shadow is esy to see in light appearance but not visible in dark appearance. It should more visible.

Brand colour

The image logo in the image card is the brand colour. Material design guidelines say brand colours can be used at full saturation in a dark theme, although application should be limited to one or two branded elements, such as a logo or a branded button. This is why the colour theme was chosen to by shades and tints of the brand logo earlier. It makes the whole app look more coherent even if it is only used very sparingly.

Flutter Material Components Android light appearance with a Card   Flutter Material Components Android dark appearance with a Card


Finding and fixing theme and colour problems with the UI

Look carefully at the screenshots and theres an issue. The expansion tile icon ( ) isn't visible when dark appearance is on. It is visible when light appearance is on so there looks to be a problem with the colour of the icon when dark appearance is selected.

This can be tricky to figure out from the theme settings above. One approach to diagnosing it is to use Android Studio to track down the problem element in order to determine its colour and styling.

Open up the flutter inspector and select 'Render Tree' Now press the crosshair to enable 'Select Widget Mode'. Now tap on the UI where the missing widget should appear.

Andrid Studio Showing the Flutter Inspector on the Render Tree

You should see the Render tree navigate to the offending widget and see it highlighted on the actual surface of the running app. Now you can examine the properties of the widget and see where they inherit their colours from.

The missing element is a 'TextSpan' in the 'ExpansionTile' widget.

Flutter Material Components Android light appearance 'Select Widgets mode'   Flutter Material Components Android dark appearance 'Select Widgets mode'

To fix this I searched the forums for 'flutter expansiontile trailing icon' to see if I could find information and as is often the case someone else had a similar issue documented in stack overflow question 60192298. The solution marked as solved suggested setting unselectedWidgetColor so just for the darkTheme add unselectedWidgetColor: darkwhichislighter[500], and save to see the change. It worked! Now the Caret symbol works in Dark appearance as expected.

That was quite difficult to troubleshot, but helpful in understanding how the theme colours are used by the MDC-Flutter components. It also makes the dark theme robust for any other components that might need the unselectedWidgetColor.

Heres the fixed screen with the 'Select Widgets mode' enabled, and then with it turned off. It looks much nicer!

Flutter Material Components Android dark appearance 'Select Widgets mode'   Flutter Material Components Android dark appearance 'Select Widgets mode'

Continue to add components

As a way to learn a bit more about the MDC-Flutter component widgets letc continue to add one of each to the page so as to see how they all look.