Flutter Skill Of ThemeExtensions And Material3

GSYTech
CodeX
Published in
5 min readJun 8, 2022

ThemeExtensions and Material3,They are all important components of Flutter 3, I think that you may have heard of them, but you haven’t used them yet.

ThemeExtensions

I believe that everyone has used Theme in Flutter. For example, you can adjust some styles by modifying the global ThemeData , such as removing the click effect of InkWell and TextButton globally.

theme: ThemeData(
primarySwatch: Colors.blue,
// remove InkWell splash click
splashFactory: NoSplash.splashFactory,
// remove InkWell click highlight
highlightColor: Colors.transparent,
textButtonTheme: TextButtonThemeData(
// remove TextButton splash click
style: ButtonStyle(splashFactory: NoSplash.splashFactory),
),
),

Of course, developers can also using Theme.of(context) to read some global styles of ThemeData, so as to make your Widget configuration more flexible.

But if there is no parameter in ThemeData that what your needs, or you want this parameter to be used only by specific Widget?

Flutter 3 provides us with a solution: ThemeExtensions.

Developers can define the extended ThemeData parameters by inheriting ThemeExtension and overriding the copyWith and lerp methods, for example:

@immutable
class StatusColors extends ThemeExtension<StatusColors> {
static const light = StatusColors(open: Colors.green, closed: Colors.red); static const dark = StatusColors(open: Colors.white, closed: Colors.brown);

const StatusColors({required this.open, required this.closed});

final Color? open;
final Color? closed;

@override
StatusColors copyWith({
Color? success,
Color? info,
}) {
return StatusColors(
open: success ?? this.open,
closed: info ?? this.closed,
);
}

@override
StatusColors lerp(ThemeExtension<StatusColors>? other, double t) {
if (other is! StatusColors) {
return this;
}
return StatusColors(
open: Color.lerp(open, other.open, t),
closed: Color.lerp(closed, other.closed, t),
);
}

@override
String toString() => 'StatusColors('
'open: $open, closed: $closed'
')';
}

After that, you can configure the StatusColors above to the extensions of Theme, and then using Theme.of(context).extension<StatusColors>() to read the configured parameters.

theme: ThemeData(
primarySwatch: Colors.blue,
extensions: <ThemeExtension<dynamic>>[
StatusColors.light,
],
),

·····

@override
Widget build(BuildContext context) {

/// get status color from ThemeExtensions
final statusColors = Theme.of(context).extension<StatusColors>();

return Scaffold(
extendBody: true,
body: Container(
alignment: Alignment.center,
child: new ElevatedButton(
style: TextButton.styleFrom(
backgroundColor: statusColors?.open,
),
onPressed: () {},
child: new Text("Button")),
),
);
}

So easy right?

Through ThemeExtensions, the third-party package can also provide corresponding ThemeExtensions objects when writing Widget, so as to achieve more flexible style configuration support.

Material3

Material3 is a new UI design specification proposed by Google in Android 12. Now in Flutter 3, you can open the configuration support through useMaterial3: true.

theme: ThemeData(
primarySwatch: Colors.blue,
useMaterial3: true,
),

Of course, before you start Material3, you need to have a certain understanding of it, because it still has a great impact on the UI style.

As shown in below, in primarySwatch: Colors.blue, the default styles of AppBar, Card, TextButton and ElevatedButton are different:

You can see that the fillet and the default color have been changed. For example:

  • The click effect and the default Dialog style have changed
  • The default OverscrollIndicator effect of list scrolling on Android has also changed

At present, the following Widgets are mainly affected by useMaterial3 in Flutter 3. It can be seen that most of the widgets with interactive effects are mainly affected:

  • [AlertDialog]
  • [AppBar]
  • [Card]
  • [Dialog]
  • [ElevatedButton]
  • [FloatingActionButton]
  • [Material]
  • [NavigationBar]
  • [NavigationRail]
  • [OutlinedButton]
  • [StretchingOverscrollIndicator]
  • [GlowingOverscrollIndicator]
  • [TextButton]

But what is the difference between Material3 and Material2?

Taking AppBar as an example, we can see that the background color acquisition methods in M2 and M3 are different.

In M3, there is no Brightness.dark judgment, does that mean that m3 does not support Diablo mode?

Before we answer this question, let’s look at what is special about _TokeDefaultsM3?

You can see from the source code, _TokeDefaultsM3 is automatically generated by script, and the current version number is v0_92, so one of the biggest differences between m3 and M2 is that its style code is now automatically generated.

From gen_defaults , You can see that basically involve M3 are automatically generated by using templates from the data under data. For example, the backgroundColor of Appbar points to the surface.

The reason why the default style of M3 no longer needs Brightness.dark judgment is made in ColorScheme used by M3.

In fact, colorScheme is the core of theme color in Flutter 3.0, and parameters such as primaryColorBrightness and primarySwatch will be discarded in the future.

Therefore, if you are still using primarySwatch, you will use in ColorScheme.fromSwatch method converted primarySwatch to ColorScheme.

ColorScheme.fromSwatch(
primarySwatch: primarySwatch,
primaryColorDark: primaryColorDark,
accentColor: accentColor,
cardColor: cardColor,
backgroundColor: backgroundColor,
errorColor: errorColor,
brightness: effectiveBrightness,
);

In addition, you can also use ColorScheme.fromSeed or colorSchemeSeed to directly configure ColorScheme in ThemeData.

But, What is ColorScheme ?

theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Color(0xFF4285F4)),
useMaterial3: true,
),

This actually involves a very interesting knowledge point: HCT color package under Material3: material-color-utilities .

In Material3, the color is not calculated completely according to RGB, but will be converted through material-color-utilities.

Through the internal CorePalette object, RGB will be converted into HCT related values for calculation and display.

HCT is actually the abbreviation of hue, chroma and tone. The HCT color space can be easily accessed through Google’s open source material-color-utilities plugin.

At present, this repo supports dart, Java, typescript and other languages. In addition, c/c++ and Object-C will also be supported soon.

Benefit from HCT, ColorScheme.fromSeed(seedColor: Color(0xFF4285F4)) can directly generate a series of theme colors through a seedcolor, which is why material3 can have more theme colors.

https://material.io/blog/science-of-color-design

Well, now you can ask your designer: Do you know what HCT is?

--

--