Flutter 主题切换实现详解
简介
主题切换是应用中常见的功能,Flutter 提供了完整的主题支持。本文介绍如何实现动态主题切换功能。
基本实现
定义主题数据
dart
class AppTheme {
static final ThemeData lightTheme = ThemeData(
brightness: Brightness.light,
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.white,
appBarTheme: AppBarTheme(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
),
textTheme: TextTheme(
bodyLarge: TextStyle(color: Colors.black87),
bodyMedium: TextStyle(color: Colors.black87),
),
);
static final ThemeData darkTheme = ThemeData(
brightness: Brightness.dark,
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.grey[900],
appBarTheme: AppBarTheme(
backgroundColor: Colors.grey[850],
foregroundColor: Colors.white,
),
textTheme: TextTheme(
bodyLarge: TextStyle(color: Colors.white),
bodyMedium: TextStyle(color: Colors.white70),
),
);
}
主题管理
dart
class ThemeProvider extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;
ThemeMode get themeMode => _themeMode;
bool get isDarkMode => _themeMode == ThemeMode.dark;
void setThemeMode(ThemeMode mode) {
_themeMode = mode;
notifyListeners();
}
void toggleTheme() {
_themeMode = isDarkMode ? ThemeMode.light : ThemeMode.dark;
notifyListeners();
}
}
完整示例
dart
// 主应用
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => ThemeProvider(),
child: Consumer<ThemeProvider>(
builder: (context, themeProvider, child) {
return MaterialApp(
title: 'Theme Demo',
theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme,
themeMode: themeProvider.themeMode,
home: HomePage(),
);
},
),
);
}
}
// 主页
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final themeProvider = Provider.of<ThemeProvider>(context);
return Scaffold(
appBar: AppBar(
title: Text('Theme Demo'),
actions: [
IconButton(
icon: Icon(
themeProvider.isDarkMode
? Icons.light_mode
: Icons.dark_mode,
),
onPressed: () => themeProvider.toggleTheme(),
),
],
),
body: ListView(
padding: EdgeInsets.all(16),
children: [
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Theme Settings',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 16),
RadioListTile<ThemeMode>(
title: Text('System'),
value: ThemeMode.system,
groupValue: themeProvider.themeMode,
onChanged: (value) {
themeProvider.setThemeMode(value!);
},
),
RadioListTile<ThemeMode>(
title: Text('Light'),
value: ThemeMode.light,
groupValue: themeProvider.themeMode,
onChanged: (value) {
themeProvider.setThemeMode(value!);
},
),
RadioListTile<ThemeMode>(
title: Text('Dark'),
value: ThemeMode.dark,
groupValue: themeProvider.themeMode,
onChanged: (value) {
themeProvider.setThemeMode(value!);
},
),
],
),
),
),
SizedBox(height: 16),
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Preview',
style: Theme.of(context).textTheme.titleLarge,
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {},
child: Text('Elevated Button'),
),
SizedBox(height: 8),
OutlinedButton(
onPressed: () {},
child: Text('Outlined Button'),
),
SizedBox(height: 8),
TextButton(
onPressed: () {},
child: Text('Text Button'),
),
SizedBox(height: 16),
TextField(
decoration: InputDecoration(
labelText: 'Input Field',
border: OutlineInputBorder(),
),
),
],
),
),
),
],
),
);
}
}
主题持久化
保存主题设置
dart
class ThemePreferences {
static const String key = 'theme_mode';
static Future<void> saveThemeMode(ThemeMode mode) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString(key, mode.toString());
}
static Future<ThemeMode> getThemeMode() async {
final prefs = await SharedPreferences.getInstance();
final value = prefs.getString(key);
return ThemeMode.values.firstWhere(
(mode) => mode.toString() == value,
orElse: () => ThemeMode.system,
);
}
}
使用持久化
dart
class ThemeProvider extends ChangeNotifier {
ThemeMode _themeMode = ThemeMode.system;
ThemeProvider() {
_loadThemeMode();
}
Future<void> _loadThemeMode() async {
_themeMode = await ThemePreferences.getThemeMode();
notifyListeners();
}
Future<void> setThemeMode(ThemeMode mode) async {
_themeMode = mode;
await ThemePreferences.saveThemeMode(mode);
notifyListeners();
}
}
最佳实践
- 合理组织主题数据
- 使用 Provider 管理状态
- 实现主题持久化
- 提供预览功能
- 支持系统主题
注意事项
- 注意性能影响
- 处理主题切换动画
- 保持主题一致性
- 适配不同平台
- 考虑可访问性
总结
通过合理使用 Flutter 的主题系统和状态管理,可以轻松实现动态主题切换功能。注意在实现过程中要考虑性能优化和用户体验。