使用ScaffoldMessenger全局Key时为SnackBar应用正确主题
问题
为实现全局调用SnackBar的功能,我参考网络示例创建了ScaffoldMessenger的Riverpod Provider,代码如下:
final scaffoldMessengerKeyProvider = Provider((ref) => GlobalKey<ScaffoldMessengerState>()); final scaffoldMessengerProvider = Provider((ref) => ref.watch(scaffoldMessengerKeyProvider).currentState!); return MaterialApp.router( theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, scaffoldMessengerKey: ref.watch(scaffoldMessengerKeyProvider), ... );
通过以下代码可在任意位置显示SnackBar:
widgetRef.read(scaffoldMessengerProvider).showSnackBar( SnackBar( content: Text('Hi, i am a SnackBar'), ), );
目前SnackBar可正常显示,但始终应用默认蓝色主题,请问如何为该ScaffoldMessenger或SnackBar应用自定义的AppTheme.lightTheme/darkTheme,有无简洁可行的实现方案?
解决方案
方案1:在自定义主题中全局配置SnackBar样式
直接在AppTheme.lightTheme和darkTheme中定义snackBarTheme,所有SnackBar会自动继承当前主题的样式,无需修改调用代码:
class AppTheme { static ThemeData get lightTheme { return ThemeData( // 其他主题配置项... snackBarTheme: SnackBarThemeData( backgroundColor: Colors.teal[700], contentTextStyle: const TextStyle(color: Colors.white, fontSize: 14), actionTextColor: Colors.amberAccent, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ); } static ThemeData get darkTheme { return ThemeData( // 其他深色主题配置项... snackBarTheme: SnackBarThemeData( backgroundColor: Colors.grey[800], contentTextStyle: const TextStyle(color: Colors.white, fontSize: 14), actionTextColor: Colors.lightBlueAccent, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), ); } }
方案2:调用时手动绑定当前主题样式
如果不需要全局配置,可在显示SnackBar时通过Theme.of(context)获取当前主题的SnackBar样式并应用:
widgetRef.read(scaffoldMessengerProvider).showSnackBar( SnackBar( content: const Text('Hi, i am a SnackBar'), backgroundColor: Theme.of(context).snackBarTheme.backgroundColor, contentTextStyle: Theme.of(context).snackBarTheme.contentTextStyle, actionTextColor: Theme.of(context).snackBarTheme.actionTextColor, ), );
注意:调用该代码的组件必须处于MaterialApp的上下文范围内,确保Theme.of(context)能获取到有效主题。
方案3:通过Riverpod关联主题状态
将主题状态纳入Provider管理,让SnackBar自动跟随当前主题切换:
- 创建主题状态Provider:
final themeModeProvider = StateProvider<ThemeMode>((ref) => ThemeMode.light); final currentThemeProvider = Provider<ThemeData>((ref) { final mode = ref.watch(themeModeProvider); return mode == ThemeMode.light ? AppTheme.lightTheme : AppTheme.darkTheme; });
- 更新
MaterialApp的主题配置:
return MaterialApp.router( theme: AppTheme.lightTheme, darkTheme: AppTheme.darkTheme, themeMode: ref.watch(themeModeProvider), scaffoldMessengerKey: ref.watch(scaffoldMessengerKeyProvider), ... );
- 显示SnackBar时读取当前主题样式:
final currentTheme = widgetRef.read(currentThemeProvider); widgetRef.read(scaffoldMessengerProvider).showSnackBar( SnackBar( content: const Text('Hi, i am a SnackBar'), backgroundColor: currentTheme.snackBarTheme.backgroundColor, contentTextStyle: currentTheme.snackBarTheme.contentTextStyle, ), );
内容的提问来源于stack exchange,提问作者redarflap
相关产品推荐
相关产品推荐

