Thèmes et styles Flutter
Cette section présentera la configuration des thèmes dans Flutter, y compris les thèmes Material Design, les thèmes personnalisés et le mode sombre.
ThemeData - Thème de l'application
L'utilisation de ThemeData vous permet de configurer uniformément les couleurs de thème de l'application, les polices, les styles, et plus encore.
Exemple : Configuration du thème de l'application
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// Couleur principale
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// Utiliser Material 3
useMaterial3: true,
// Police
fontFamily: 'Roboto',
// Thème de l'AppBar
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// Thème des boutons
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// Thème du champ de saisie
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
runApp(
MaterialApp(
theme: ThemeData(
// Couleur principale
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// Utiliser Material 3
useMaterial3: true,
// Police
fontFamily: 'Roboto',
// Thème de l'AppBar
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// Thème des boutons
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// Thème du champ de saisie
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
Theme.of - Utilisation du thème
Utilisez Theme.of(context) dans un Widget pour obtenir le thème actuel.
Exemple : Utilisation des couleurs du thème
class ThemedButton extends StatelessWidget {
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Obtenir le thème
final theme = Theme.of(context);
return Column(
children: [
// Utiliser la couleur du thème
Conteneur(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur primaire',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// Utiliser la couleur secondaire
Conteneur(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur secondaire',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// Utiliser la couleur d'erreur
Conteneur(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur d'erreur',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Obtenir le thème
final theme = Theme.of(context);
return Column(
children: [
// Utiliser la couleur du thème
Conteneur(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur primaire',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// Utiliser la couleur secondaire
Conteneur(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur secondaire',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// Utiliser la couleur d'erreur
Conteneur(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'Couleur d'erreur',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
Mode sombre
Exemple : Prise en charge du mode sombre
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// Thème clair
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// Thème sombre
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// Activer les deux (facultatif)
themeMode: ThemeMode.system, // Selon les paramètres système
// themeMode: ThemeMode.light // Forcer le mode clair
// themeMode: ThemeMode.dark // Forcer le mode sombre
home: const ThemeTogglePage(),
),
);
}
// Basculer le thème
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Changement de thème')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Thème actuel'),
const SizedBox(height: 20),
// Bouton de bascule du thème
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// Passer en mode sombre
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// Passer en mode clair
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('Basculer le thème'),
),
],
),
),
);
}
}
runApp(
MaterialApp(
theme: ThemeData(
// Thème clair
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// Thème sombre
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// Activer les deux (facultatif)
themeMode: ThemeMode.system, // Selon les paramètres système
// themeMode: ThemeMode.light // Forcer le mode clair
// themeMode: ThemeMode.dark // Forcer le mode sombre
home: const ThemeTogglePage(),
),
);
}
// Basculer le thème
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Changement de thème')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Thème actuel'),
const SizedBox(height: 20),
// Bouton de bascule du thème
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// Passer en mode sombre
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// Passer en mode clair
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('Basculer le thème'),
),
],
),
),
);
}
}
Extensions de style personnalisées
Exemple : TextTheme personnalisé
⟦⟧ThemeData(
textTheme: const TextTheme(
// Texte d'affichage (titre principal)
displayLarge: TextStyle(fontSize⟦⟧fontWeight⟦⟧FontWeight.: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// Texte de titre
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// Texte de titre
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// Texte du corps
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// Texte d'étiquette
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
textTheme: const TextTheme(
// Texte d'affichage (titre principal)
displayLarge: TextStyle(fontSize⟦⟧fontWeight⟦⟧FontWeight.: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// Texte de titre
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// Texte de titre
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// Texte du corps
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// Texte d'étiquette
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
autres extensionsL'utilisation de ThemeData pour gérer de manière centralisée les styles de l'application facilite le changement de thème et le maintien de la cohérence des styles, simplifiant la maintenance.