Flutter Themes and Styling
This section will introduce theme configuration in Flutter, including Material Design themes, custom themes, and dark mode.
ThemeData - App Theme
Using ThemeData allows you to uniformly configure the app's theme colors, fonts, styles, and more.
Example: Configuring the App Theme
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// Primary color
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// Use Material 3
useMaterial3: true,
// Font
fontFamily: 'Roboto',
// AppBar theme
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// Button theme
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// Input field theme
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
runApp(
MaterialApp(
theme: ThemeData(
// Primary color
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
// Use Material 3
useMaterial3: true,
// Font
fontFamily: 'Roboto',
// AppBar theme
appBarTheme: const AppBarTheme(
centerTitle: true,
elevation: 0,
),
// Button theme
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
// Input field theme
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
filled: true,
),
),
home: const MyHomePage(),
),
);
}
Theme.of - Using the Theme
Use Theme.of(context) in a Widget to get the current theme.
Example: Using Theme Colors
class ThemedButton extends StatelessWidget {
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Get theme
final theme = Theme.of(context);
return Column(
children: [
// Use theme color
Container(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'Primary color',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// Use secondary color
Container(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'Secondary color',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// Use error color
Container(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'Error color',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
const ThemedButton({super.key});
@override
Widget build(BuildContext context) {
// Get theme
final theme = Theme.of(context);
return Column(
children: [
// Use theme color
Container(
color: theme.colorScheme.primary,
padding: const EdgeInsets.all(16),
child: Text(
'Primary color',
style: TextStyle(color: theme.colorScheme.onPrimary),
),
),
const SizedBox(height: 16),
// Use secondary color
Container(
color: theme.colorScheme.secondary,
padding: const EdgeInsets.all(16),
child: Text(
'Secondary color',
style: TextStyle(color: theme.colorScheme.onSecondary),
),
),
const SizedBox(height: 16),
// Use error color
Container(
color: theme.colorScheme.error,
padding: const EdgeInsets.all(16),
child: Text(
'Error color',
style: TextStyle(color: theme.colorScheme.onError),
),
),
],
);
}
}
Dark Mode
Example: Dark Mode Support
void main() {
runApp(
MaterialApp(
theme: ThemeData(
// Light theme
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// Dark theme
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// Enable both (optional)
themeMode: ThemeMode.system, // Based on system settings
// themeMode: ThemeMode.light // Force light mode
// themeMode: ThemeMode.dark // Force dark mode
home: const ThemeTogglePage(),
),
);
}
// Toggle theme
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Theme Switch')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Current Theme'),
const SizedBox(height: 20),
// Toggle theme button
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// Switch to dark mode
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// Switch to light mode
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('Toggle Theme'),
),
],
),
),
);
}
}
runApp(
MaterialApp(
theme: ThemeData(
// Light theme
brightness: Brightness.light,
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
),
darkTheme: ThemeData(
// Dark theme
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
),
// Enable both (optional)
themeMode: ThemeMode.system, // Based on system settings
// themeMode: ThemeMode.light // Force light mode
// themeMode: ThemeMode.dark // Force dark mode
home: const ThemeTogglePage(),
),
);
}
// Toggle theme
class ThemeTogglePage extends StatelessWidget {
const ThemeTogglePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Theme Switch')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Current Theme'),
const SizedBox(height: 20),
// Toggle theme button
ElevatedButton(
onPressed: () {
final currentMode = Theme.of(context).brightness;
if (currentMode == Brightness.light) {
// Switch to dark mode
Theme.of(context).setThemeMode(ThemeMode.dark);
} else {
// Switch to light mode
Theme.of(context).setThemeMode(ThemeMode.light);
}
},
child: const Text('Toggle Theme'),
),
],
),
),
);
}
}
Custom Style Extensions
Example: Custom TextTheme
ThemeData(
textTheme: const TextTheme(
// Display text (headline)
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// Title text
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// Title text
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// Body text
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// Label text
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
textTheme: const TextTheme(
// Display text (headline)
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.w400),
displayMedium: TextStyle(fontSize: 45, fontWeight: FontWeight.w400),
displaySmall: TextStyle(fontSize: 36, fontWeight: FontWeight.w400),
// Title text
headlineLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.w400),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w400),
headlineSmall: TextStyle(fontSize: 24, fontWeight: FontWeight.w400),
// Title text
titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
titleMedium: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
titleSmall: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
// Body text
bodyLarge: TextStyle(fontSize: 16, fontWeight: FontWeight.w400),
bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.w400),
bodySmall: TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
// Label text
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
labelMedium: TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
labelSmall: TextStyle(fontSize: 11, fontWeight: FontWeight.w500),
),
)
other extensionsUsing ThemeData to centrally manage app styles makes it easy to switch themes and maintain style consistency, simplifying maintenance.