Dynamische Farben und adaptive helle/dunkle Themes
Passen Sie Ihre Farbpalette an das Hintergrundbild der Nutzer an und wechseln Sie nahtlos zwischen hellem und dunklem Modus.
Dynamische Farben und adaptive helle/dunkle Themes ist eine kostenlose Flutter Mobile Development-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Flutter Mobile Development-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Flutter Mobile Development-Kurs umfasst insgesamt 4 Lektionen.
Teile dieser Lektion wurden noch nicht übersetzt und werden auf Englisch angezeigt.
Why Dynamic Color Matters
Material 3 introduced dynamic color: an app's palette can be derived from the user's wallpaper (Android 12+) so your UI feels personal and native to the device.
- On supported devices, the system exposes a
ColorSchemesourced from the wallpaper. - On older devices or other platforms, you fall back to a brand seed color.
- The same logic must produce both a light and a dark scheme.
In this lesson you'll wire up dynamic color, build adaptive light/dark themes, and let the system decide which one to show.
Seed Color as the Foundation
Even with dynamic color, you always need a fallback. Material 3's ColorScheme.fromSeed generates a full, accessible palette from a single seed color.
- Pass
brightnessto get the matching light or dark variant. - The generated scheme guarantees correct contrast between roles like
primaryandonPrimary.
import 'package:flutter/material.dart';
final ColorScheme lightScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.light,
);
final ColorScheme darkScheme = ColorScheme.fromSeed(
seedColor: const Color(0xFF6750A4),
brightness: Brightness.dark,
);Building Light and Dark ThemeData
A ThemeData wraps a ColorScheme plus typography and component styles. With Material 3 you set useMaterial3: true and feed in the scheme.
- Create one
ThemeDataper brightness. - Keep them consistent by deriving both from the same seed.
ThemeData buildTheme(ColorScheme scheme) {
return ThemeData(
useMaterial3: true,
colorScheme: scheme,
appBarTheme: AppBarTheme(
backgroundColor: scheme.surface,
foregroundColor: scheme.onSurface,
),
);
}Letting the System Pick the Mode
MaterialApp accepts both a theme (light) and a darkTheme. The themeMode property decides which is active.
ThemeMode.systemfollows the OS setting automatically.ThemeMode.light/ThemeMode.darkforce a mode (useful for an in-app toggle).
With ThemeMode.system, Flutter switches seamlessly when the user flips dark mode in their device settings.
MaterialApp(
theme: buildTheme(lightScheme),
darkTheme: buildTheme(darkScheme),
themeMode: ThemeMode.system,
home: const HomePage(),
);Reading Dynamic Color from the System
The dynamic_color package exposes the wallpaper-based palette via the DynamicColorBuilder widget. Its builder gives you optional light and dark ColorSchemes.
- If the device supports dynamic color, both schemes are non-null.
- If not, they are
nulland you fall back to your seed.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
DynamicColorBuilder(
builder: (ColorScheme? lightDynamic, ColorScheme? darkDynamic) {
final light = lightDynamic ?? lightScheme;
final dark = darkDynamic ?? darkScheme;
return MaterialApp(
theme: buildTheme(light),
darkTheme: buildTheme(dark),
themeMode: ThemeMode.system,
home: const HomePage(),
);
},
);Harmonizing Brand Colors
When you blend dynamic wallpaper colors with your brand color, the two can clash. The harmonize helpers shift a custom color toward the dynamic primary so accents feel cohesive.
- Use
harmonizeWithon aColoragainst the scheme's primary. - This keeps custom semantic colors (success, warning) on-brand with the wallpaper.
import 'package:dynamic_color/dynamic_color.dart';
import 'package:flutter/material.dart';
ColorScheme harmonizeScheme(ColorScheme scheme) {
return scheme.harmonized();
}
Color harmonizeBrand(Color brand, ColorScheme scheme) {
return brand.harmonizeWith(scheme.primary);
}Color Roles, Not Hard-Coded Hex
For themes to adapt, widgets must read semantic roles from Theme.of(context).colorScheme instead of hard-coded colors.
scheme.primarywithscheme.onPrimaryfor prominent actions.scheme.surfacewithscheme.onSurfacefor backgrounds and text.scheme.surfaceContainerHighestfor subtle cards.
Because these roles flip with brightness, your widgets become light/dark agnostic automatically.
Widget buildCard(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Container(
color: scheme.surfaceContainerHighest,
child: Text(
'Adaptive',
style: TextStyle(color: scheme.onSurface),
),
);
}Pure Dart: Picking a Scheme by Brightness
The decision logic for which scheme to use is plain Dart. Here is a tiny, runnable model of the fallback rule: prefer the dynamic scheme, otherwise use the seed-derived one.
- This mirrors the
lightDynamic ?? lightSchemepattern. - No Flutter widgets needed — just the selection rule.
enum Brightness { light, dark }
String chooseScheme({
required Brightness brightness,
required bool supportsDynamic,
}) {
final base = supportsDynamic ? 'dynamic' : 'seed';
return '$base-${brightness.name}';
}
void main() {
print(chooseScheme(brightness: Brightness.dark, supportsDynamic: true));
print(chooseScheme(brightness: Brightness.light, supportsDynamic: false));
}An In-App Theme Toggle
Users often want to override the system. Store a ThemeMode in state and pass it to MaterialApp. A ValueNotifier is a lightweight way to rebuild on change.
- Default to
ThemeMode.systemso wallpaper/dark-mode still apply. - Let the toggle pick light, dark, or back to system.
final themeModeNotifier = ValueNotifier<ThemeMode>(ThemeMode.system);
ValueListenableBuilder<ThemeMode>(
valueListenable: themeModeNotifier,
builder: (context, mode, _) {
return MaterialApp(
theme: buildTheme(lightScheme),
darkTheme: buildTheme(darkScheme),
themeMode: mode,
home: const HomePage(),
);
},
);Reacting to the Effective Brightness
Inside widgets you sometimes need to know which mode is actually rendering (for example, to pick a different illustration). Read it from the active theme, not from the device, because an in-app toggle may override the system.
Theme.of(context).brightnessreflects the resolved theme.- Avoid
MediaQuery.platformBrightnessOfwhen a toggle can override it.
Widget heroImage(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
return Image.asset(
isDark ? 'assets/hero_dark.png' : 'assets/hero_light.png',
);
}Testing Both Modes Quickly
Always verify your UI in both schemes before shipping. Two practical habits:
- Toggle dark mode in the device/emulator settings to confirm
ThemeMode.systemreacts. - Temporarily force
themeMode: ThemeMode.darkto catch hard-coded colors and low-contrast text.
Common bugs: a hard-coded Colors.black text that vanishes on a dark surface, or a custom accent that never harmonized with the dynamic palette.
Quick Check: Choosing themeMode
You want your app to automatically match the user's wallpaper-based dynamic colors AND follow their OS light/dark setting, while still allowing an optional in-app override later. What is the right baseline configuration?
Recap: Adaptive Material 3 Theming
You built a palette that adapts to both wallpaper and brightness:
- Seed fallback:
ColorScheme.fromSeedfor light and dark when dynamic color is unavailable. - Dynamic color:
DynamicColorBuildersupplies wallpaper schemes, with?? seedSchemefallback. - Harmonization: blend brand and custom colors toward the dynamic primary.
- Semantic roles: read
colorSchemeroles instead of hard-coded hex so widgets flip automatically. - Mode control:
themeMode: ThemeMode.systemby default, with an optionalValueNotifiertoggle.
Adapt to the user, fall back gracefully, and never hard-code a color you could read from the scheme.
Häufig gestellte Fragen
Ist die Lektion „Dynamische Farben und adaptive helle/dunkle Themes“ kostenlos?
Ja — der vollständige Text von „Dynamische Farben und adaptive helle/dunkle Themes“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Flutter Mobile Development-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Flutter Mobile Development-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Dynamische Farben und adaptive helle/dunkle Themes“?
Passen Sie Ihre Farbpalette an das Hintergrundbild der Nutzer an und wechseln Sie nahtlos zwischen hellem und dunklem Modus. Du übst Flutter Mobile Development mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Flutter Mobile Development zu starten?
Keine Vorkenntnisse erforderlich. Flutter Mobile Development auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.
Wie lange dauert die Lektion „Dynamische Farben und adaptive helle/dunkle Themes“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Flutter Mobile Development-Lektion Code schreiben und ausführen?
Ja. Jede Flutter Mobile Development-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Material-3-Farbschemata und Seed-Farben
- Dynamische Farben und adaptive helle/dunkle Themes
- Eigene ThemeExtension für Brand-Tokens
- Responsive Typografie und Theming von Komponenten