Themes và Styling trong Flutter
1. ThemeData
Định nghĩa theme cho toàn app:
MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
brightness: Brightness.light,
),
darkTheme: ThemeData(
brightness: Brightness.dark,
),
themeMode: ThemeMode.system, // Theo hệ thống
home: MyApp(),
)2. ColorScheme
Cách hiện đại để định nghĩa colors:
ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
useMaterial3: true,
)Custom ColorScheme
ColorScheme(
brightness: Brightness.light,
primary: Color(0xFF6200EE),
onPrimary: Colors.white,
secondary: Color(0xFF03DAC6),
onSecondary: Colors.black,
error: Color(0xFFB00020),
onError: Colors.white,
surface: Colors.white,
onSurface: Colors.black,
)3. Sử dụng Theme trong Code
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Container(
color: theme.primaryColor,
child: Text(
'Hello',
style: theme.textTheme.headlineMedium,
),
);
}4. TextTheme
ThemeData(
textTheme: TextTheme(
displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.bold),
headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.w600),
bodyLarge: TextStyle(fontSize: 16),
bodyMedium: TextStyle(fontSize: 14),
labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
),
)
// Sử dụng
Text('Title', style: Theme.of(context).textTheme.headlineMedium)5. Custom Fonts
Thêm font vào pubspec.yaml
flutter:
fonts:
- family: Roboto
fonts:
- asset: assets/fonts/Roboto-Regular.ttf
- asset: assets/fonts/Roboto-Bold.ttf
weight: 700Áp dụng vào theme
ThemeData(
fontFamily: 'Roboto',
textTheme: TextTheme(
bodyLarge: TextStyle(fontFamily: 'Roboto'),
),
)6. Dark Mode
Toggle Dark Mode
class MyApp extends StatefulWidget {
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _themeMode = ThemeMode.system;
void toggleTheme() {
setState(() {
_themeMode = _themeMode == ThemeMode.light
? ThemeMode.dark
: ThemeMode.light;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(useMaterial3: true),
darkTheme: ThemeData.dark(useMaterial3: true),
themeMode: _themeMode,
home: HomeScreen(onToggleTheme: toggleTheme),
);
}
}Với Provider
class ThemeProvider extends ChangeNotifier {
ThemeMode _mode = ThemeMode.system;
ThemeMode get mode => _mode;
void toggle() {
_mode = _mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}7. Widget-specific Themes
ThemeData(
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
cardTheme: CardTheme(
elevation: 4,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
appBarTheme: AppBarTheme(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
elevation: 0,
),
)8. Theme Extensions
Custom theme properties:
// Định nghĩa extension
@immutable
class AppColors extends ThemeExtension<AppColors> {
final Color? success;
final Color? warning;
const AppColors({this.success, this.warning});
@override
ThemeExtension<AppColors> copyWith({Color? success, Color? warning}) {
return AppColors(
success: success ?? this.success,
warning: warning ?? this.warning,
);
}
@override
ThemeExtension<AppColors> lerp(ThemeExtension<AppColors>? other, double t) {
if (other is! AppColors) return this;
return AppColors(
success: Color.lerp(success, other.success, t),
warning: Color.lerp(warning, other.warning, t),
);
}
}
// Thêm vào theme
ThemeData(
extensions: [
AppColors(success: Colors.green, warning: Colors.orange),
],
)
// Sử dụng
final colors = Theme.of(context).extension<AppColors>()!;
Container(color: colors.success)9. Complete Theme Example
class AppTheme {
static ThemeData light = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.light,
),
fontFamily: 'Roboto',
appBarTheme: AppBarTheme(
centerTitle: true,
elevation: 0,
),
cardTheme: CardTheme(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
);
static ThemeData dark = ThemeData(
useMaterial3: true,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.blue,
brightness: Brightness.dark,
),
fontFamily: 'Roboto',
// ... same widget themes
);
}
// main.dart
MaterialApp(
theme: AppTheme.light,
darkTheme: AppTheme.dark,
)📝 Tóm tắt
| Component | Mục đích |
|---|---|
ThemeData | Theme chính |
ColorScheme | Palette màu |
TextTheme | Typography |
ThemeMode | Light/Dark/System |
Theme.of(context) | Truy cập theme |
ThemeExtension | Custom properties |
Last updated on