Thémes et stylisation Flutter
Introduction aux thèmes Flutter
Section titled “Introduction aux thèmes Flutter”Flutter offre un système de thématisation puissant basé sur Material Design qui permet de personnaliser l’apparence de votre application de manière cohérente. Le système de thèmes permet de définir des couleurs, des polices, des formes et d’autres propriétés visuelles qui seront appliquées automatiquement à travers l’application.
ThemeData
Section titled “ThemeData”ThemeData est la classe centrale pour définir l’apparence de votre application Flutter. Elle contient toutes les informations de style qui seront héritées par les widgets descendants.
Configuration de base
Section titled “Configuration de base”MaterialApp( theme: ThemeData( primarySwatch: Colors.blue, fontFamily: 'Roboto', ), home: MyHomePage(),)Propriétés principales de ThemeData
Section titled “Propriétés principales de ThemeData”Les widgets d’interface utilisateur peuvent être personnalisés graphiquement. Dans les versions récentes de Flutter, chaque composant dispose de son propre “sous-thème” :
ThemeData.inputDecorationTheme:InputDecorationThemeThemeData.sliderTheme:SliderThemeDataThemeData.switchTheme:SwitchThemeDataThemeData.checkboxTheme:CheckboxThemeDataThemeData.radioTheme:RadioThemeDataThemeData.popupMenuTheme:PopupMenuThemeDataThemeData.toggleableActiveColor:ColorThemeData.unselectedWidgetColor:Color
Material Design et couleurs
Section titled “Material Design et couleurs”Palette de couleurs Material Design
Section titled “Palette de couleurs Material Design”Material Design propose une palette de MaterialColors avec plusieurs nuances pour chaque couleur :
// Couleurs de baseColors.cyanColors.cyan.shade100Colors.cyan.shade500Colors.cyan.shade900
// Couleurs d'accentColors.cyanAccentColors.cyanAccent.shade100Utilisation des couleurs
Section titled “Utilisation des couleurs”Container( color: Colors.blue.shade300, child: Text( 'Texte avec couleur de fond', style: TextStyle(color: Colors.white), ),)Référence complète : Material Design Colors
Gestion des thèmes sombres et clairs
Section titled “Gestion des thèmes sombres et clairs”Flutter prend en charge les thèmes sombres et clairs avec une transition animée automatique.
Configuration dans MaterialApp
Section titled “Configuration dans MaterialApp”MaterialApp( title: 'Mon App', theme: ThemeData.light(), // Thème clair darkTheme: ThemeData.dark(), // Thème sombre themeMode: ThemeMode.system, // Suit les préférences système home: MyHomePage(),)Propriétés de thème avancées
Section titled “Propriétés de thème avancées”theme: Thème principal (généralement clair)darkTheme: Thème sombrehighContrastTheme: Thème à fort contrastehighContrastDarkTheme: Thème sombre à fort contrastethemeMode: Mode de thème (system,light,dark)
Exemple de thème personnalisé
Section titled “Exemple de thème personnalisé”ThemeData customLightTheme = ThemeData( primarySwatch: Colors.indigo, brightness: Brightness.light, fontFamily: 'Roboto', textTheme: TextTheme( headline1: TextStyle(fontSize: 32, fontWeight: FontWeight.bold), bodyText1: TextStyle(fontSize: 16), ),);
ThemeData customDarkTheme = ThemeData( primarySwatch: Colors.indigo, brightness: Brightness.dark, fontFamily: 'Roboto', textTheme: TextTheme( headline1: TextStyle(fontSize: 32, fontWeight: FontWeight.bold), bodyText1: TextStyle(fontSize: 16), ),);Extensions de thème
Section titled “Extensions de thème”Depuis Flutter 3, il est possible d’enrichir ThemeData avec vos propres classes de thématisation personnalisées.
Création d’une extension de thème
Section titled “Création d’une extension de thème”Vous pouvez ajouter des extensions personnalisées à votre thème :
ThemeData.light().copyWith( extensions: <ThemeExtension<dynamic>>{ MyThemeExtension(), },)Vous pouvez ajouter plusieurs extensions selon vos besoins.
Implémentation d’une ThemeExtension
Section titled “Implémentation d’une ThemeExtension”Chaque extension X doit étendre ThemeExtension<X> et override deux méthodes obligatoires : copyWith et lerp.
class MyThemeExtension extends ThemeExtension<MyThemeExtension> { final Color customColor; final double customSpacing;
const MyThemeExtension({ required this.customColor, required this.customSpacing, });
@override ThemeExtension<MyThemeExtension> copyWith({ Color? customColor, double? customSpacing, }) { return MyThemeExtension( customColor: customColor ?? this.customColor, customSpacing: customSpacing ?? this.customSpacing, ); }
@override ThemeExtension<MyThemeExtension> lerp( ThemeExtension<MyThemeExtension>? other, double t, ) { if (other is! MyThemeExtension) { return this; }
return MyThemeExtension( customColor: Color.lerp(customColor, other.customColor, t) ?? customColor, customSpacing: lerpDouble(customSpacing, other.customSpacing, t) ?? customSpacing, ); }}Méthode copyWith
Section titled “Méthode copyWith”La méthode copyWith permet de créer des copies modifiées de l’extension :
@overrideThemeExtension<MyThemeExtension> copyWith({ Color? newCustomColor,}) => MyThemeExtension( customColor: newCustomColor ?? customColor,);Méthode lerp
Section titled “Méthode lerp”La méthode lerp permet de calculer des interpolations entre 2 valeurs afin d’animer une transition :
@overrideThemeExtension<MyThemeExtension> lerp( ThemeExtension<MyThemeExtension>? other, double t,) { if (other is! MyThemeExtension) { return this; }
return MyThemeExtension( customColor: Color.lerp(customColor, other.customColor, t) ?? customColor, );}Utilisation d’une extension de thème
Section titled “Utilisation d’une extension de thème”Pour utiliser votre extension personnalisée dans un widget :
final MyThemeExtension myThemeExtension = Theme.of(context).extension<MyThemeExtension>()!;
Container( color: myThemeExtension.customColor, padding: EdgeInsets.all(myThemeExtension.customSpacing), child: Text('Contenu stylisé'),)Approches de stylisation personnalisée
Section titled “Approches de stylisation personnalisée”Stylisation au niveau des widgets
Section titled “Stylisation au niveau des widgets”Chaque widget peut être stylisé individuellement :
Text( 'Mon texte', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.blue, ),)Utilisation du thème global
Section titled “Utilisation du thème global”Récupérer les styles depuis le thème de l’application :
Text( 'Mon texte', style: Theme.of(context).textTheme.headline6,)Styles conditionnels selon le thème
Section titled “Styles conditionnels selon le thème”Container( color: Theme.of(context).brightness == Brightness.dark ? Colors.grey[800] : Colors.grey[200], child: Text( 'Contenu adaptatif', style: Theme.of(context).textTheme.bodyText1, ),)Exemple complet d’application avec thèmes
Section titled “Exemple complet d’application avec thèmes”import 'package:flutter/material.dart';
void main() { runApp(MyApp());}
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'App avec thèmes', theme: ThemeData( primarySwatch: Colors.blue, brightness: Brightness.light, fontFamily: 'Roboto', extensions: <ThemeExtension<dynamic>>{ MyThemeExtension( customColor: Colors.blue.shade100, customSpacing: 16.0, ), }, ), darkTheme: ThemeData( primarySwatch: Colors.blue, brightness: Brightness.dark, fontFamily: 'Roboto', extensions: <ThemeExtension<dynamic>>{ MyThemeExtension( customColor: Colors.blue.shade900, customSpacing: 16.0, ), }, ), themeMode: ThemeMode.system, home: MyHomePage(), ); }}
class MyHomePage extends StatelessWidget { @override Widget build(BuildContext context) { final myTheme = Theme.of(context).extension<MyThemeExtension>()!;
return Scaffold( appBar: AppBar( title: Text('Exemple de thème'), ), body: Container( color: myTheme.customColor, padding: EdgeInsets.all(myTheme.customSpacing), child: Column( children: [ Text( 'Titre principal', style: Theme.of(context).textTheme.headline4, ), SizedBox(height: myTheme.customSpacing), Text( 'Texte de contenu avec style personnalisé', style: Theme.of(context).textTheme.bodyText1, ), ], ), ), ); }}Bonnes pratiques
Section titled “Bonnes pratiques”Organisation des thèmes
Section titled “Organisation des thèmes”- Centralisez vos thèmes : Créez des fichiers dédiés pour vos définitions de thèmes
- Utilisez des extensions : Pour des propriétés personnalisées spécifiques à votre app
- Respectez Material Design : Restez cohérent avec les principes de design de Google
- Testez les deux modes : Vérifiez que votre app fonctionne bien en mode clair et sombre
Gestion des couleurs
Section titled “Gestion des couleurs”- Utilisez ColorScheme : Pour une palette cohérente
- Prévoyez l’accessibilité : Testez les contrastes pour les utilisateurs malvoyants
- Adaptez-vous au système : Respectez les préférences utilisateur
Performance
Section titled “Performance”- Évitez les recréations : Réutilisez les instances de ThemeData
- Utilisez const : Pour les widgets statiques
- Optimisez les transitions : Les méthodes lerp doivent être efficaces