Flutter中如何让setSystemUIOverlayStyle颜色随主题模式动态变化?
解决SystemUiOverlayStyle随系统主题切换不生效的问题
问题原因
你当前的代码仅在Widget重建(比如页面导航)时执行SystemChrome.setSystemUIOverlayStyle,但系统主题切换时,当前页面的Widget不会自动触发build,导致样式没有同步更新。
解决方案
方案1:通过WidgetsBindingObserver监听主题变化
让页面的State类混入WidgetsBindingObserver,监听系统亮度变化事件,实时更新UI样式:
class _YourPageState extends State<YourPage> with WidgetsBindingObserver { // 简化深色模式判断逻辑 bool isDarkModeOn(BuildContext context) => Theme.of(context).brightness == Brightness.dark; void _updateSystemUiStyle() { final systemThemeLight = SystemUiOverlayStyle.light.copyWith( systemNavigationBarColor: const Color(0xdfd6f5ca), systemNavigationBarIconBrightness: Brightness.light, ); final systemThemeDark = SystemUiOverlayStyle.dark.copyWith( systemNavigationBarColor: Colors.black, systemNavigationBarIconBrightness: Brightness.light, ); SystemChrome.setSystemUIOverlayStyle( isDarkModeOn(context) ? systemThemeDark : systemThemeLight ); } @override void initState() { super.initState(); // 注册系统事件监听 WidgetsBinding.instance.addObserver(this); // 初始化时设置一次样式 _updateSystemUiStyle(); } @override void didChangePlatformBrightness() { super.didChangePlatformBrightness(); // 系统亮度变化时触发样式更新 _updateSystemUiStyle(); } @override void dispose() { // 页面销毁时取消监听 WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override Widget build(BuildContext context) { // 你的页面布局代码 return Scaffold(body: ...); } }
方案2:用AnimatedBuilder监听Theme变化
借助AnimatedBuilder监听Theme.of(context)的变化,自动触发样式更新:
@override Widget build(BuildContext context) { return AnimatedBuilder( animation: Theme.of(context), builder: (context, child) { final systemThemeLight = SystemUiOverlayStyle.light.copyWith( systemNavigationBarColor: const Color(0xdfd6f5ca), systemNavigationBarIconBrightness: Brightness.light, ); final systemThemeDark = SystemUiOverlayStyle.dark.copyWith( systemNavigationBarColor: Colors.black, systemNavigationBarIconBrightness: Brightness.light, ); SystemChrome.setSystemUIOverlayStyle( Theme.of(context).brightness == Brightness.dark ? systemThemeDark : systemThemeLight ); return child!; }, child: Scaffold( // 你的页面布局内容 ), ); }
方案3:依赖MediaQuery触发build
让build方法依赖MediaQuery.of(context).platformBrightness,系统主题变化时会自动触发build更新样式:
@override Widget build(BuildContext context) { // 依赖系统亮度值,确保主题变化时触发build final isDark = MediaQuery.of(context).platformBrightness == Brightness.dark; final systemThemeLight = SystemUiOverlayStyle.light.copyWith( systemNavigationBarColor: const Color(0xdfd6f5ca), systemNavigationBarIconBrightness: Brightness.light, ); final systemThemeDark = SystemUiOverlayStyle.dark.copyWith( systemNavigationBarColor: Colors.black, systemNavigationBarIconBrightness: Brightness.light, ); SystemChrome.setSystemUIOverlayStyle(isDark ? systemThemeDark : systemThemeLight); return Scaffold(body: ...); }
注意事项
- 方案1是最直接的系统事件监听方式,适合单页面或全局的样式同步需求;
- 方案2、3通过Widget重建触发更新,需确保当前Widget会因主题变化而重建;
- 如果是全局主题切换场景,也可以在
MaterialApp的builder方法中统一处理系统UI样式。
内容的提问来源于stack exchange,提问作者Fabian M
相关产品推荐
相关产品推荐

