Flutter中根据主题切换全局颜色的实现方法
实现主题切换下的动态颜色配置
1. 重构颜色类,支持双主题配置
把原有的静态常量拆分成浅色、深色两套配置,通过主题模式返回对应颜色:
class ThemeColors { // 浅色主题颜色集 static const _light = { 'primary': Color.fromRGBO(25, 155, 241, 1), 'secondaryFont': Color.fromRGBO(100, 100, 100, 1), 'primaryFont': Colors.black, 'background': Color.fromRGBO(245, 245, 245, 1), 'successToast': Color.fromRGBO(218, 255, 226, 1), 'warningToast': Color.fromRGBO(255, 236, 199, 1), 'errorToast': Color.fromRGBO(255, 157, 136, 1), 'noticeBadWeather': Color.fromRGBO(41, 41, 41, 1), 'noticeUrgent': Color.fromRGBO(199, 31, 46, 1), 'noticeImportant': Color.fromRGBO(252, 192, 78, 1), 'noticeRegular': Color.fromRGBO(115, 161, 184, 1), // 其他浅色颜色 }; // 深色主题颜色集 static const _dark = { 'primary': Color.fromRGBO(30, 160, 250, 1), 'secondaryFont': Color.fromRGBO(180, 180, 180, 1), 'primaryFont': Colors.white, 'background': Color.fromRGBO(30, 30, 30, 1), 'successToast': Color.fromRGBO(60, 200, 80, 1), 'warningToast': Color.fromRGBO(255, 200, 120, 1), 'errorToast': Color.fromRGBO(255, 120, 100, 1), 'noticeBadWeather': Color.fromRGBO(200, 200, 200, 1), 'noticeUrgent': Color.fromRGBO(255, 60, 70, 1), 'noticeImportant': Color.fromRGBO(255, 220, 100, 1), 'noticeRegular': Color.fromRGBO(140, 180, 200, 1), // 其他深色颜色 }; // 根据主题模式获取对应颜色 static Color _get(String key, ThemeMode mode) { return mode == ThemeMode.light ? _light[key] ?? Colors.transparent : _dark[key] ?? Colors.transparent; } // 封装成直观的属性方法,方便调用 static Color primary(ThemeMode mode) => _get('primary', mode); static Color secondaryFont(ThemeMode mode) => _get('secondaryFont', mode); static Color primaryFont(ThemeMode mode) => _get('primaryFont', mode); static Color background(ThemeMode mode) => _get('background', mode); static Color successToast(ThemeMode mode) => _get('successToast', mode); static Color warningToast(ThemeMode mode) => _get('warningToast', mode); static Color errorToast(ThemeMode mode) => _get('errorToast', mode); static Color noticeBadWeather(ThemeMode mode) => _get('noticeBadWeather', mode); static Color noticeUrgent(ThemeMode mode) => _get('noticeUrgent', mode); static Color noticeImportant(ThemeMode mode) => _get('noticeImportant', mode); static Color noticeRegular(ThemeMode mode) => _get('noticeRegular', mode); }
2. 创建主题状态管理Provider
这个类负责管理当前主题模式,处理SharedPreferences的读写,通过ChangeNotifier通知UI更新:
import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; class ThemeProvider extends ChangeNotifier { ThemeMode _currentMode = ThemeMode.light; ThemeMode get currentMode => _currentMode; // 初始化时读取本地保存的主题 ThemeProvider() { _loadSavedTheme(); } Future<void> _loadSavedTheme() async { final prefs = await SharedPreferences.getInstance(); final isDark = prefs.getBool('isDarkTheme') ?? false; _currentMode = isDark ? ThemeMode.dark : ThemeMode.light; notifyListeners(); } // 切换主题并保存到本地 Future<void> toggleTheme() async { _currentMode = _currentMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light; final prefs = await SharedPreferences.getInstance(); await prefs.setBool('isDarkTheme', _currentMode == ThemeMode.dark); notifyListeners(); } }
3. 在应用中配置Provider并使用动态颜色
首先在main函数中注入Provider:
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; void main() { runApp( ChangeNotifierProvider( create: (_) => ThemeProvider(), child: const MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { final themeProvider = Provider.of<ThemeProvider>(context); return MaterialApp( theme: ThemeData.light(), darkTheme: ThemeData.dark(), themeMode: themeProvider.currentMode, home: const HomePage(), ); } }
然后在UI组件中调用动态颜色:
class HomePage extends StatelessWidget { const HomePage({super.key}); @override Widget build(BuildContext context) { final themeMode = Provider.of<ThemeProvider>(context).currentMode; return Scaffold( backgroundColor: ThemeColors.background(themeMode), appBar: AppBar( backgroundColor: ThemeColors.primary(themeMode), title: Text( '主题切换示例', style: TextStyle(color: ThemeColors.primaryFont(themeMode)), ), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( '测试文本', style: TextStyle( color: ThemeColors.secondaryFont(themeMode), fontSize: 18, ), ), const SizedBox(height: 20), ElevatedButton( onPressed: () { Provider.of<ThemeProvider>(context, listen: false).toggleTheme(); }, child: const Text('切换主题'), ), ], ), ), ); } }
补充说明
- 如果追求类型安全,可以把
_light和_dark换成实体类(比如LightColorConfig、DarkColorConfig),再通过ThemeColors返回对应实例,避免字符串key的潜在错误。 - 不需要切换的颜色可以保留原静态常量,按需调整即可。
内容的提问来源于stack exchange,提问作者rafaelpadu
相关产品推荐
相关产品推荐

