0Pricing
Flutter Mobile Development · Lezione

Colore dinamico e temi chiaro/scuro adattivi

Adatti la palette allo sfondo scelto dall’utente e passi senza interruzioni tra modalità chiara e scura.

Colore dinamico e temi chiaro/scuro adattivi è una lezione Flutter Mobile Development gratuita su CoddyKit. Questa è la lezione 2 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Flutter Mobile Development, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Flutter Mobile Development include 4 lezioni in totale.

Parti di questa lezione non sono ancora state tradotte e vengono mostrate in inglese.

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 ColorScheme sourced 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 brightness to get the matching light or dark variant.
  • The generated scheme guarantees correct contrast between roles like primary and onPrimary.
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 ThemeData per 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.system follows the OS setting automatically.
  • ThemeMode.light / ThemeMode.dark force 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 null and 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 harmonizeWith on a Color against 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.primary with scheme.onPrimary for prominent actions.
  • scheme.surface with scheme.onSurface for backgrounds and text.
  • scheme.surfaceContainerHighest for 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 ?? lightScheme pattern.
  • 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.system so 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).brightness reflects the resolved theme.
  • Avoid MediaQuery.platformBrightnessOf when 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.system reacts.
  • Temporarily force themeMode: ThemeMode.dark to 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.fromSeed for light and dark when dynamic color is unavailable.
  • Dynamic color: DynamicColorBuilder supplies wallpaper schemes, with ?? seedScheme fallback.
  • Harmonization: blend brand and custom colors toward the dynamic primary.
  • Semantic roles: read colorScheme roles instead of hard-coded hex so widgets flip automatically.
  • Mode control: themeMode: ThemeMode.system by default, with an optional ValueNotifier toggle.

Adapt to the user, fall back gracefully, and never hard-code a color you could read from the scheme.

Domande Frequenti

La lezione «Colore dinamico e temi chiaro/scuro adattivi» è gratuita?

Sì — il testo completo di «Colore dinamico e temi chiaro/scuro adattivi» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Flutter Mobile Development, passa a CoddyKit PRO. Il corso Flutter Mobile Development include 4 lezioni in totale.

Cosa imparerò in «Colore dinamico e temi chiaro/scuro adattivi»?

Adatti la palette allo sfondo scelto dall’utente e passi senza interruzioni tra modalità chiara e scura. Eserciti Flutter Mobile Development con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Flutter Mobile Development?

Non è richiesta alcuna esperienza precedente. Flutter Mobile Development su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 2 di 4.

Quanto tempo richiede la lezione «Colore dinamico e temi chiaro/scuro adattivi»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Flutter Mobile Development?

Sì. Ogni lezione Flutter Mobile Development include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Schemi colore Material 3 e colori seed
  2. Colore dinamico e temi chiaro/scuro adattivi
  3. ThemeExtension personalizzata per i token del brand
  4. Tipografia responsive e tematizzazione dei componenti
← Torna a Flutter Mobile Development