Theme et ThemeData — définition, principes et configuration des styles

Auteur : IT Sectr Publié le : 2026-07-03 Temps de lecture : 8 min

Theme et ThemeData — les mécanismes centraux de thématisation dans Flutter, permettant de définir les couleurs, polices, marges et styles de composants globalement pour toute l'application. ThemeData est un objet de configuration passé à MaterialApp via le paramètre theme. Selon la documentation officielle de Flutter (2026), une configuration correcte de ThemeData réduit le code de style dupliqué de 70 à 80 % et assure une apparence visuelle uniforme sur tous les écrans. Le système d'héritage intégré permet de surcharger le thème au niveau de widgets individuels via Theme.of(context).

Points essentiels

  • ThemeData — objet de configuration avec palette de couleurs, typographie et styles de composants
  • Theme.of(context) — accès au thème actuel depuis n'importe quel widget via BuildContext
  • Light/Dark — prise en charge intégrée des thèmes clair et sombre via theme et darkTheme
  • Theme — widget qui hérite le thème aux éléments enfants et permet de le surcharger
  • ColorScheme — ensemble de couleurs harmonieuses générant des styles pour tout le système Material

Que sont Theme et ThemeData

ThemeData est une classe contenant la description complète du style visuel d'une application Material. Elle est passée à MaterialApp via le paramètre theme ou darkTheme et est héritée par tous les widgets enfants. Chaque widget Material Design utilise ThemeData pour obtenir ses styles : couleurs des boutons, tailles de l'AppBar, styles de texte, marges des cartes et icônes.

Au cœur de ThemeData se trouve ColorScheme, qui définit les couleurs primary, secondary, surface, error et autres. À partir de ces couleurs, les états (hover, focus, pressed) sont automatiquement calculés pour tous les composants Material. Par exemple, ElevatedButton utilise la couleur primary pour le fond et onPrimary pour le texte — sans configuration supplémentaire.

Le widget Theme est un InheritedWidget qui propage le thème vers le bas dans l'arbre de widgets. Tout widget peut accéder au thème actuel via Theme.of(context) et peut également créer un nouveau thème basé sur l'existant avec des valeurs surchargées via Theme.copyWith ou ThemeData.copyWith.

En résumé : ThemeData est la source unique de styles de l'application. Commencez le développement en définissant ThemeData — cela définit le langage visuel de tout le projet et évite les styles dispersés sur différents écrans.

ColorScheme : la base de la palette de couleurs

ColorScheme est l'élément central de la thématisation dans Material 3. Il remplace les obsolètes primarySwatch et primaryColor, fournissant un ensemble complet de couleurs pour tous les états et composants.

ColorScheme contient 12 couleurs principales : primary, onPrimary, secondary, onSecondary, surface, onSurface, error, onError, background, onBackground, outline et shadow. Pour chaque couleur, les variantes claire et sombre sont automatiquement calculées, ainsi que les couleurs pour les états hover, focus, pressed et dragged. Lorsque seul primary est spécifié, le framework génère automatiquement les couleurs restantes via ColorScheme.fromSeed.

La méthode ColorScheme.fromSeed (Material 3) prend une couleur de base seedColor et génère une palette harmonieuse complète basée sur l'algorithme Material Design 3. Cela élimine le besoin de sélection manuelle des couleurs complémentaires et analogues. Il suffit de passer une couleur de marque primaire, et ColorScheme.fromSeed crée une palette cohérente pour tout le système Material.

En résumé : dans les nouveaux projets, utilisez ColorScheme.fromSeed pour générer la palette. Pour la compatibilité Material 2 — utilisez primarySwatch. ColorScheme est le minimum requis pour Material 3.

Typographie et TextTheme : polices de l'application

TextTheme est une partie de ThemeData qui définit les styles de texte pour tous les niveaux de titres, sous-titres, corps et étiquettes. Material Design définit 15 styles de texte : headlineLarge, headlineMedium, headlineSmall, titleLarge, titleMedium et autres.

La typographie est définie soit via GoogleFonts pour le chargement automatique des polices, soit via le Theme.of(context).textTheme intégré avec des objets TextStyle personnalisés. GoogleFonts fournit des centaines de polices via le package google_fonts, qui les met en cache localement après le premier chargement. L'alternative consiste à incorporer les polices dans les assets du projet via pubspec.yaml.

Pour une typographie adaptative, TextTheme prend en charge MediaQuery.textScaleFactor — lorsque la taille de la police système augmente, tous les styles de texte sont mis à l'échelle proportionnellement. De plus, différentes tailles de police peuvent être définies pour différents facteurs de forme via isTest en fonction de MediaQuery.size.width.

En résumé : définissez TextTheme dans ThemeData et utilisez Theme.of(context).textTheme pour tous les éléments de texte. Cela assure la cohérence des polices et simplifie les modifications globales de typographie.

Héritage et surcharge du thème

Theme est un InheritedWidget qui propage le thème des parents aux enfants. Tout widget enfant peut à la fois lire le thème actuel via Theme.of(context) et créer sa propre copie avec des modifications via ThemeData.copyWith.

Mécanisme d'héritage : si un widget est enveloppé dans un Theme avec de nouvelles données, tous ses descendants voient le thème surchargé, tandis que les widgets en dehors de cette enveloppe voient l'original. Cela permet, par exemple, d'isoler les styles pour un écran spécifique : un en-tête utilise un thème personnalisé avec un AppBarTheme modifié, tandis que le reste de l'application utilise le thème standard.

L'imbrication de Theme peut être illimitée. Flutter utilise une recherche hiérarchique : lors de l'appel de Theme.of(context), le framework remonte l'arbre jusqu'au premier Theme et retourne son thème. Si aucun Theme n'est trouvé — une exception est levée. Par conséquent, MaterialApp enveloppe toujours l'application dans un Theme.

En résumé : l'héritage de Theme est un mécanisme flexible pour isoler les styles. Utilisez la surcharge du thème pour des écrans individuels sans dupliquer la configuration globale.

Thème sombre : mode sombre de l'application

Thème sombre est la capacité intégrée de Flutter à basculer entre les thèmes clair et sombre. ThemeData est stocké dans les paramètres theme (clair) et darkTheme (sombre) de MaterialApp. Le paramètre themeMode contrôle le mode : ThemeMode.light (toujours clair), ThemeMode.dark (toujours sombre) ou ThemeMode.system (suit les paramètres système).

Lors de l'implémentation d'un thème sombre, il n'est pas nécessaire de recréer tous les styles à partir de zéro. Il suffit de passer ColorScheme.fromSeed(seedColor, brightness: Brightness.dark) à darkTheme. Le framework ajustera automatiquement les couleurs pour un fond sombre : surface devient gris foncé, le texte devient clair. Les autres sous-thèmes (AppBarTheme, CardTheme, BottomNavigationBarTheme) sont hérités de la version claire sauf s'ils sont explicitement surchargés.

Pour des transitions fluides entre les thèmes, Flutter fournit une animation via AnimatedTheme. Lors du changement de themeMode, les couleurs et les styles s'animent, créant une transition visuellement agréable. AnimatedTheme utilise Duration et Curve pour configurer la vitesse d'animation.

En résumé : le thème sombre est implémenté via darkTheme et ColorScheme.fromSeed avec brightness: Brightness.dark. Utilisez ThemeMode.system pour suivre les paramètres système de l'utilisateur.

Exemples de code avec Theme et ThemeData

Exemple 1 — configuration globale du thème via MaterialApp en utilisant ColorScheme.fromSeed.

dart
final ThemeData appTheme = ThemeData(
  useMaterial3: true,
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.indigo,
    brightness: Brightness.light,
  ),
  appBarTheme: const AppBarTheme(
    centerTitle: true,
    elevation: 0,
  ),
  cardTheme: const CardTheme(
    elevation: 2,
    margin: EdgeInsets.all(8),
  ),
);

return MaterialApp(
  theme: appTheme,
  themeMode: ThemeMode.system,
  home: const MyHomePage(),
);

Cet exemple crée un ThemeData avec Material 3, un jeu de couleurs basé sur l'indigo et des styles personnalisés d'AppBar et de Card. useMaterial3 active le nouveau système de thèmes Material 3, et ColorScheme.fromSeed génère la palette complète.

Exemple 2 — accès au thème et surcharge pour une partie de l'application.

dart
Widget build(BuildContext context) {
  final theme = Theme.of(context);

  return Column(
    children: [
      Text(
        'Standard headline',
        style: theme.textTheme.headlineMedium,
      ),
      Theme(
        data: theme.copyWith(
          colorScheme: theme.colorScheme.copyWith(
            primary: Colors.orange,
          ),
        ),
        child: const SpecialSection(),
      ),
    ],
  );
}

Le deuxième exemple montre l'utilisation de Theme.of(context) pour lire les styles et Theme() avec copyWith pour surcharger le thème dans une partie de l'arbre sans modifier la configuration globale. SpecialSection à l'intérieur de Theme recevra la couleur primary orange, tandis que le reste de l'application conserve l'indigo original.

En résumé : le thème global est défini dans MaterialApp, accessible via Theme.of(context) et surchargé via Theme avec copyWith. Pour Material 3, utilisez ColorScheme.fromSeed.

Erreurs typiques de configuration du thème

Erreur 1 : utiliser primarySwatch au lieu de ColorScheme dans Material 3. primarySwatch est obsolète et non supporté dans Material 3. Lors de l'utilisation de useMaterial3: true avec primarySwatch, Flutter émet un avertissement. Solution : migrer vers ColorScheme.fromSeed pour la génération de la palette.

Erreur 2 : coder en dur les couleurs dans les widgets au lieu d'utiliser Theme.of(context). Les développeurs écrivent Colors.blue directement dans un Container au lieu de la couleur primary ou secondary du thème. Lors du changement de thème, ces couleurs restent inchangées, brisant la cohérence du style. Solution : utilisez toujours Theme.of(context).colorScheme.primary ou d'autres couleurs du thème.

Erreur 3 : absence de darkTheme. Si l'application ne définit pas darkTheme, lorsque le thème sombre est activé sur l'appareil, Flutter tente d'adapter automatiquement le thème clair, ce qui donne souvent un résultat de mauvaise qualité. Solution : passez toujours darkTheme à MaterialApp, même si le thème sombre n'est pas une priorité — c'est une UX importante pour les utilisateurs.

Erreur 4 : créer un nouveau thème à chaque build. Si ThemeData est créé dans la méthode build, chaque reconstruction du widget crée un nouvel objet de thème, brisant l'optimisation d'InheritedWidget. Solution : déplacer ThemeData vers un champ static ou un constructeur const en dehors de build.

En résumé : une thématisation correcte nécessite une approche centralisée. Déplacez ThemeData dans des constantes, utilisez les jeux de couleurs du thème et définissez toujours les deux thèmes — clair et sombre.

Questions fréquentes

Quelle est la différence entre Theme et ThemeData ?

ThemeData sont les données de configuration (couleurs, polices, styles). Theme est un InheritedWidget qui transmet ThemeData vers le bas dans l'arbre de widgets. Theme.of(context) retourne le ThemeData que le Theme le plus proche propage dans le contexte actuel.

Comment basculer dynamiquement le thème de l'application ?

Contrôlez themeMode dans MaterialApp via l'état de l'application. Changez l'état de ThemeMode.light à ThemeMode.dark, et Flutter reconstruira tout l'arbre avec le nouveau thème. Pour une animation fluide, utilisez AnimatedTheme.

Qu'est-ce que ColorScheme.fromSeed ?

ColorScheme.fromSeed est une méthode Material 3 qui prend une couleur de base (seedColor) et génère une palette harmonieuse complète : primary, secondary, tertiary, surface, error et leurs variantes on. Permet d'obtenir un jeu de couleurs cohérent à partir d'une seule couleur de marque.

Comment utiliser des polices personnalisées avec Theme ?

Via TextTheme à l'intérieur de ThemeData : spécifiez TextStyle avec fontFamily pour chaque niveau. Pour Google Fonts, utilisez le package google_fonts, en passant fontFamily directement à TextTheme. Pour les polices locales — incluez-les via pubspec.yaml dans la section fonts.

Peut-on surcharger le thème pour un seul écran ?

Oui. Enveloppez l'écran dans un Theme avec des données surchargées via copyWith. Tous les widgets enfants à l'intérieur de ce Theme recevront les styles modifiés, tandis que le reste de l'application conserve le thème original. Cela ne crée pas de surcharge supplémentaire.

Résumé

  • ThemeData — objet de configuration avec palette de couleurs, typographie et styles de tous les composants Material
  • ColorScheme.fromSeed — la principale façon de générer une palette de couleurs dans Material 3 à partir d'une seule couleur de marque
  • Theme.of(context) — accès au thème actuel pour lire les styles sans duplication de code
  • Theme — InheritedWidget pour hériter et surcharger le thème dans un sous-arbre de widgets
  • Thème sombre — ThemeData séparé avec brightness: Brightness.dark, contrôlé via themeMode
  • Recommandation : déplacez ThemeData dans static ou const, définissez toujours theme et darkTheme dans MaterialApp

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi