This is the fourth part of my journey to build and publish a Flutter based app for the App Store and Google Play.
Dark and light text theme
This is just some boilerplate text. It is in headline6
text style. headline6
is parchmentLightOnSurface
in the light theme and parchmentDarkOnSurface
on the dark theme and should change colour automatically when the theme is changed. This is so simple compared to writing specific code to support colour changes.


The baseline Material color theme is ten years old and was supplemented by a dark theme baseline palette. It provides exaclty what it says - a baseline from which to iterate your colour design.
TL:DR – The addition of dark appearance was unfairly derided at the time but is now a critical part of application design thinking. Address it early on in your design process or it will be hard to add later.
Contents
Dark and light appearance
All iOS and Android devices before Android 10 and iOS 13 had one appearance - light appearance. Dark theme was introduced in Android 10, and Dark appearance in iOS 13. Throughout this blog the word 'appearance' will be used for system setting and 'theme' will just be about the app being built.
Dark appearance has proven very popular among end users due to the better usability in low light and perhaps claimed battery improvements. There won't be any new devices that don't support it so light only devices is a legacy device support issue now. This means that supporting the system settings that change the device from light to dark appearance must be supported for apps so as not to look anachronistic on new devices. So lets revisit the Material guidelines for dark themes.
System Settings Behaviour
The guidelines talk about having a setting in the app but this is perhaps unnecessary. This app will simply respect the system setting for the device. There won't be a separate control. This is a more usual expected behaviour for apps, and is less work!
Baseline Material color theme and dark theme baseline palette
The 2014 baseline theme as originally designed had 12 colours named and defined. The dark theme baseline palette more recently added only has 11 colours. Secondary variant is no more. No idea why. Nevertheless it is important to define all these colours for our theme so as to make sure that the app displays as expected on all supported devices. Importantly remember the device can determine automatically whether to switch from light to dark appearance by time of day, rule or external sensor for example. Take the colour table from the previous article and modify it for dark appearance so as to see the entire colour pallette. This is why in the last article we created the darkwhichislight
palette in addition to the lightwhichisdark
one.
Primary 500 #6200EE |
Primary 200 #BB86FC |
Primary Variant 700 #3700B3 |
Primary Variant 700 #3700B3 |
Secondary 200 #03DAC6 |
Secondary 200 #03DAC6 |
Secondary Variant #018786 |
|
Background #FFFFFF |
Background #121212 |
Surface #FFFFFF |
Surface #121212 |
Error #B00020 |
Error #CF6679 |
On Primary #FFFFFF |
On Primary #000000 |
On Secondary #000000 |
On Secondary #000000 |
On Background #000000 |
On Background #FFFFFF |
On Surface #000000 |
On Surface #FFFFFF |
On Error #FFFFFF |
On Error #000000 |
The . The "On" colors above are primarily applied on top of key surfaces that use a primary, secondary, surface, background, or error color. By default, dark theme “on” colors are white and black. When adjusting the custom theme these will mainly stay on the defaults.
Custom Material color theme extended to cover dark appearance
Putting the two themes like this is helpful to identify any clashes.
Primary 500 #892807 |
Primary 200 #EC7C55 |
Primary Variant 700 #570000 |
Primary Variant 700 #E76944 |
Secondary 200 #ec7c55 |
Secondary 200 #F6BEAA |
Secondary Variant #bf5531 |
|
Background #FFFFFF |
Background #121212 |
Surface #FFFFFF |
Surface #121212 |
Error #C5032B |
Error #CF6679 |
On Primary #FFFFFF |
On Primary #000000 |
On Secondary #000000 |
On Secondary #000000 |
On Background #000000 |
On Background #FFFFFF |
On Surface #000000 |
On Surface #FFFFFF |
On Error #FFFFFF |
On Error #000000 |
Apply the custom colours to your theme in the app
Edit main.dart
. Note that swatches are groups of colours in material shades, and named individual colours need to be identified specifically even if they are a part of a swatch.
To use the elements of existing themes and just define the aspects of the theme that concern your app ise the copywith
method on Theme.of(context)
. This looks up the widget tree and returns the first theme found which is the default theme, and creates a theme for this apps context with the changes we have defined merged into the default theme.
theme: ThemeData(
primarySwatch: lightwhichisdarker,
primaryColor: lightwhichisdarker[500],
scaffoldBackgroundColor: parchmentLightBackground,
textTheme: Theme.of(context).textTheme.copyWith(
headline1: TextStyle(color: parchmentLightOnSurface),
headline2: TextStyle(color: parchmentLightOnSurface),
headline3: TextStyle(color: parchmentLightOnSurface),
headline4: TextStyle(color: parchmentLightOnSurface),
headline5: TextStyle(color: parchmentLightOnSurface),
headline6: TextStyle(color: parchmentLightOnSurface),
subtitle1: TextStyle(color: parchmentLightOnSurface),
subtitle2: TextStyle(color: parchmentLightOnSurface),
bodyText1: TextStyle(color: parchmentLightOnSurface),
bodyText2: TextStyle(color: parchmentLightOnSurface),
button: TextStyle(color: parchmentLightOnSurface),
caption: TextStyle(color: parchmentLightOnSurface),
overline: TextStyle(color: parchmentLightOnSurface),
),
),
...
darkTheme: ThemeData(
primarySwatch: darkwhichislighter,
primaryColor: darkwhichislighter[500],
scaffoldBackgroundColor: parchmentDarkBackground,
textTheme: Theme.of(context).textTheme.copyWith(
headline1: TextStyle(color: parchmentDarkOnSurface),
headline2: TextStyle(color: parchmentDarkOnSurface),
headline3: TextStyle(color: parchmentDarkOnSurface),
headline4: TextStyle(color: parchmentDarkOnSurface),
headline5: TextStyle(color: parchmentDarkOnSurface),
headline6: TextStyle(color: parchmentDarkOnSurface),
subtitle1: TextStyle(color: parchmentDarkOnSurface),
subtitle2: TextStyle(color: parchmentDarkOnSurface),
bodyText1: TextStyle(color: parchmentDarkOnSurface),
bodyText2: TextStyle(color: parchmentDarkOnSurface),
button: TextStyle(color: parchmentDarkOnSurface),
caption: TextStyle(color: parchmentDarkOnSurface),
overline: TextStyle(color: parchmentDarkOnSurface),
),
),
Make the app show you the theme
It can be helpful to have a page in the app which shows you the common components and what they look like. This is useful for testing different devices, however you will need to make test pages do not appear in the production app. Test data like 'lorem ipsum' text will fail Apple's App Store review guidelines.
),
body: Center(
// child: RaisedButton(
child: Padding(
padding: EdgeInsets.all(16.0),
child: 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.headline6,
)