How To Upgrade Color Scheme When Material Design Spec Changes
Material Design 3 changed to now having surface tone roles and fixed accent color roles, this is how to update color scheme when changes like that happen.
Look, Material Design spec changes always appear last in the Flutter SDK, long after the web and android native SDK changes. Let me show you one of the ways to get the design edge right now by having access to those changes today rather than 10 months from now!
Sharing raises every app designer skills, Flutter Google Developer Experts took this to mean having to do legacy Domain Driven Design and Clean Arch boilerplat3e like UseCase classes that no app designer uses anymore.
To raise your design skills and the design skills of your friends
Material Design Color Scheme Changes
Recently, Material Design spec was updated to add surface color tones and fixed accent colors:
Light Surface roles
Dark Surface roles
Fixed Accent colors
According to the Color Roles page:
Material Design Color Roles page
https://m3.material.io/styles/color/roles
Extending Color Scheme directly would not work, so we can use Dart method extensions to add methods to the Color class and use the added methods per UI element item. Then when the new Color Scheme appears in the SDK, we can change the temp methods back to using the new Color Scheme stuff.
Now, let me show you the two extensions.
Color Extensions For New Color Scheme Colors
The Surface Color Tone roles require both a seed color and the dark mode boolean:
// Copyright 2024 Fredrick Allan Grott. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:material_color_utilities/material_color_utilities.dart'; | |
/// Material Design 3 breaking change is that surfaces | |
/// get color tones thus depreciating the need for elevation | |
/// overlays. | |
/// Those being depreciated are: | |
/// surface tint colors | |
/// elevation overlays | |
/// opacity overlays | |
/// backgroundColor | |
/// onBackgroundColor | |
/// surfaceVariant | |
/// Per issue 115912, see | |
/// https://github.com/flutter/flutter/issues/115912 | |
/// | |
/// This is meant to be used with my PaneContainer. | |
/// | |
/// | |
/// | |
/// @author Fredrick Allan Grott | |
extension SurfaceColorRolesExtension on Color { | |
getSurface(Color seed, bool darkMode){ | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 6 :98)); | |
} | |
getSurfaceDim(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 6: 87)); | |
} | |
getSurfaceBright(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 24: 98)); | |
} | |
getSurfaceContainerLowest(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 4: 100)); | |
} | |
getSurfaceContainerLow(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 10: 96)); | |
} | |
getSurfaceContainer(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 12: 94)); | |
} | |
getSurfaceContainerHigh(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 17: 92)); | |
} | |
getSurfaceContainerHighest(Color seed, bool darkMode) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.neutral.get(darkMode ? 22 : 90)); | |
} | |
} |
I use the CorePalette class from the Material Color Utilities library to grab the right palette based on seed color and compute the correct color based on tone. A similar scheme is used for fixed colors, except I do not have to grab the dark mode boolean:
// Copyright 2024 Fredrick Allan Grott. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
import 'package:flutter/material.dart'; | |
import 'package:material_color_utilities/material_color_utilities.dart'; | |
/// Per issue 137683 Md3 gets fixed accetn colors | |
/// see https://github.com/flutter/flutter/issues/137683 | |
/// | |
/// Also see https://m3.material.io/styles/color/roles | |
/// | |
/// @author Fredrick Allan Grott | |
extension FixedAccentColorRolesExtension on Color { | |
getPrimaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.primary.get(90)); | |
} | |
getOnPrimaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.primary.get(10)); | |
} | |
getPrimaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.primary.get(80)); | |
} | |
getOnPrimaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.primary.get(30)); | |
} | |
getSecondaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.secondary.get(90)); | |
} | |
getOnSecondaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.secondary.get(10)); | |
} | |
getSecondaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.secondary.get(80)); | |
} | |
getOnSecondaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.secondary.get(30)); | |
} | |
getTertiaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.tertiary.get(90)); | |
} | |
getOnTertiaryFixed(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.tertiary.get(10)); | |
} | |
getTertiaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.tertiary.get(80)); | |
} | |
getOnTertiaryFixedDim(Color seed) { | |
CorePalette p = CorePalette.of(seed.value); | |
return Color(p.tertiary.get(30)); | |
} | |
} |
The code can be found in my fredgrott helper stack in my master flutter GitHub repo:
https://github.com/fredgrott/master_flutter
With Flutter Google Developer Experts sharing such classics as adding useless UseCase class boilerplate because they read about legacy Domain Driven Design and Clean Arch; it makes it hard to get the top design and flutter dev tips. Unless, you subscribe to my flutter newsletter where I am in fact curating the top design and dev tips from Very Good Ventures, GSkinner, RydMike, and many more.