Flutter AppBar设置systemNavigationBarColor后导航栏颜色不更新
最小可复现代码:
class MyPage extends StatelessWidget { @override Widget build(BuildContext context) { int count = 0; Widget child = FooPage(); return StatefulBuilder( builder: (_, update) { return Scaffold( floatingActionButton: FloatingActionButton( onPressed: () => update(() => child = (++count).isEven ? FooPage() : BarPage()), ), body: child, ); }, ); } } class FooPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Foo'), systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.black, systemNavigationBarColor: Colors.black, ), ), ); } } class BarPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Bar'), systemOverlayStyle: SystemUiOverlayStyle( statusBarColor: Colors.grey, systemNavigationBarColor: Colors.grey, ), ), ); } }
问题现象
Android端运行上述代码时,通过StatefulBuilder切换Scaffold的body子组件过程中,状态栏颜色可跟随页面配置正常变化,但系统导航栏颜色始终保持初始值不更新。子页面通过直接替换body属性加载,未使用Navigator做路由跳转。
产生原因
核心原因是Flutter中嵌套Scaffold对系统UI样式的更新逻辑存在差异:
- 状态栏样式的更新由所有可见层级的AppBar触发,只要内层Scaffold的AppBar完成构建,就会向上覆写状态栏对应的
SystemUiOverlayStyle属性,因此切换页面时状态栏颜色可以正常同步。 - 系统导航栏样式默认仅由当前路由栈对应的最外层Scaffold负责注册和更新。上述代码中FooPage、BarPage内的Scaffold是外层根Scaffold的body子组件,不属于路由栈顶层的主Scaffold,其配置的
systemNavigationBarColor不会被系统UI的监听器捕获,因此无法触发原生侧的导航栏颜色更新。
只有当Scaffold作为路由栈的顶层页面时(比如通过Navigator push进入的新页面),其配置的系统导航栏样式才会生效。
修复方案
- 方案1:移除子页面内的嵌套Scaffold,全局仅保留最外层一个根Scaffold,切换页面时直接更新根Scaffold的AppBar及
systemOverlayStyle配置,避免多层Scaffold嵌套。 - 方案2:如果必须保留子页面的Scaffold结构,在切换子页面的回调中,手动调用系统API更新导航栏样式:
// 切到对应页面时主动设置匹配的导航栏颜色 SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( systemNavigationBarColor: Colors.grey, )); - 方案3:涉及多页面切换场景优先使用Navigator管理路由栈,入栈的新页面对应的Scaffold会自动成为顶层Scaffold,无需额外处理即可触发系统导航栏颜色更新。
内容的提问来源于stack exchange,提问作者iDecode
相关产品推荐
相关产品推荐

