0Pricing
Flutter Mobile Development · Aula

Cores Dinâmicas e Temas Claro/Escuro Adaptáveis

Adapte sua paleta ao papel de parede do usuário e alterne facilmente entre os modos claro e escuro.

Cores Dinâmicas e Temas Claro/Escuro Adaptáveis é uma aula grátis de Flutter Mobile Development no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Flutter Mobile Development, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Flutter Mobile Development inclui 4 aulas no total.

Partes desta aula ainda não foram traduzidas e aparecem em inglês.

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.

Perguntas Frequentes

A aula “Cores Dinâmicas e Temas Claro/Escuro Adaptáveis” é grátis?

Sim — o texto completo de “Cores Dinâmicas e Temas Claro/Escuro Adaptáveis” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Flutter Mobile Development, atualize para CoddyKit PRO. O curso de Flutter Mobile Development inclui 4 aulas no total.

O que vou aprender em “Cores Dinâmicas e Temas Claro/Escuro Adaptáveis”?

Adapte sua paleta ao papel de parede do usuário e alterne facilmente entre os modos claro e escuro. Você pratica Flutter Mobile Development com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Flutter Mobile Development?

Nenhuma experiência prévia é necessária. Flutter Mobile Development no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Cores Dinâmicas e Temas Claro/Escuro Adaptáveis”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Flutter Mobile Development?

Sim. Cada aula de Flutter Mobile Development inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Esquemas de Cores do Material 3 e Cores de Semente
  2. Cores Dinâmicas e Temas Claro/Escuro Adaptáveis
  3. ThemeExtension Personalizado para Tokens de Marca
  4. Tipografia Responsiva e Tematização de Componentes
← Voltar para Flutter Mobile Development