Kodokon kodokon.com

Thèmes : ThemeData, Material 3 et mode sombre

Centralisez couleurs et typographies dans ThemeData, générez une palette Material 3 avec ColorScheme.fromSeed et offrez un mode sombre sans effort.

9 min · 3 questions

Ouvrir cette leçon dans Kodokon

Cesser de styler widget par widget est un cap professionnel : ThemeData centralise couleurs, typographies et formes pour toute l'application. Avec Material 3 (activé par défaut depuis Flutter 3.16), tout part du ColorScheme : ColorScheme.fromSeed dérive d'une seule couleur graine une palette complète, harmonieuse et accessible.

DART
import 'package:flutter/material.dart';

void main() {
  runApp(const ShopApp());
}

class ShopApp extends StatelessWidget {
  const ShopApp({super.key});

  @override
  Widget build(BuildContext context) {
    const seed = Colors.teal;
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
        ),
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: seed,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: ThemeMode.system,
      home: Scaffold(
        appBar: AppBar(title: const Text('Boutique')),
        body: const Center(child: Text('Bienvenue')),
      ),
    );
  }
}
Deux thèmes générés d'une seule couleur graine.

Dans vos widgets, ne réinventez rien : lisez le thème ambiant avec Theme.of(context). Le colorScheme expose des rôles sémantiques (primary, onPrimary, primaryContainer, surface...) et textTheme des styles nommés (titleMedium, bodyLarge...). Un widget écrit ainsi s'adapte automatiquement au thème clair comme au sombre.

DART
import 'package:flutter/material.dart';

class PriceTag extends StatelessWidget {
  const PriceTag({super.key, required this.price});

  final double price;

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).colorScheme;
    final text = Theme.of(context).textTheme;
    return Container(
      padding: const EdgeInsets.symmetric(
        horizontal: 12,
        vertical: 6,
      ),
      decoration: BoxDecoration(
        color: colors.primaryContainer,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Text(
        '$price €',
        style: text.titleMedium?.copyWith(
          color: colors.onPrimaryContainer,
        ),
      ),
    );
  }
}
Aucune couleur en dur : le widget suit le thème actif.

Pour aller plus loin, configurez les thèmes de composants : chaque famille de widgets (barres d'application, boutons, champs de saisie) accepte un thème dédié dans ThemeData. Vous définissez une fois le rembourrage de vos boutons ou le centrage des titres, et chaque instance en hérite sans le moindre style local.

DART
import 'package:flutter/material.dart';

final ThemeData appTheme = ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.teal,
  ),
  appBarTheme: const AppBarTheme(
    centerTitle: true,
    elevation: 0,
  ),
  filledButtonTheme: FilledButtonThemeData(
    style: FilledButton.styleFrom(
      padding: const EdgeInsets.symmetric(
        horizontal: 24,
        vertical: 12,
      ),
    ),
  ),
);
Les réglages de composants s'appliquent à toute l'application.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Que produit ColorScheme.fromSeed(seedColor: ...) ?
    • Une seule couleur légèrement éclaircie
    • Une palette Material 3 complète et cohérente dérivée de la couleur graine
    • Un dégradé pour les arrière-plans
    • Un thème sombre uniquement
  2. Comment faire suivre à l'application le réglage clair/sombre du système ?
    • Fournir uniquement theme, le reste est automatique
    • Fournir theme et darkTheme, et régler themeMode sur ThemeMode.system
    • Appeler setState quand la luminosité change
    • Lire MediaQuery dans chaque widget
  3. Pourquoi écrire color: Theme.of(context).colorScheme.primary plutôt que color: Colors.blue ?
    • C'est plus court à écrire
    • La couleur s'adapte au thème actif et reste cohérente dans toute l'application
    • Colors.blue est déprécié en Material 3