Flutter中如何为不同页面设置不同的系统导航栏颜色?
Flutter中如何为不同页面设置不同的系统导航栏颜色?
我太懂这种踩坑的感觉了——重复写导航栏颜色设置的代码不说,颜色还不听话,一会儿正常一会儿出问题,确实让人头大。咱们先捋清楚你当前代码的问题,再给你几个更靠谱的复用方案。
为什么你的代码会出现颜色异常?
你当前在页面的initState里设置绿色导航栏,dispose里恢复白色,但这里有个关键的点:dispose方法只有当页面被彻底从路由栈中移除(比如用户pop出页面且不会再返回)时才会执行。
举个例子:当你从绿色页面push到另一个页面时,绿色页面其实还在路由栈里,并没有被销毁,所以它的dispose根本没触发;等你从新页面返回绿色页面时,绿色页面的initState也不会再次执行,这就导致导航栏一直停留在新页面设置的白色,只有当绿色页面被彻底销毁再重新创建时,颜色才会正常——这就是为什么只有一个页面能正常显示绿色的原因。
方案一:封装工具类+页面可见性监听
首先把导航栏颜色设置的逻辑抽成工具类,避免重复写代码:
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; class SystemNavBarHelper { // 设置为绿色导航栏 static void setGreenNavBar() { SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( systemNavigationBarColor: Color.fromARGB(255, 52, 114, 70), systemNavigationBarIconBrightness: Brightness.dark, statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, ), ); } // 恢复为白色导航栏 static void setWhiteNavBar() { SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle( systemNavigationBarColor: Colors.white, systemNavigationBarIconBrightness: Brightness.dark, statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, ), ); } }
然后在需要绿色导航栏的页面中,通过WidgetsBindingObserver监听页面的可见状态,确保页面回到前台时能重新设置颜色:
class GreenNavBarPage extends StatefulWidget { const GreenNavBarPage({super.key}); @override State<GreenNavBarPage> createState() => _GreenNavBarPageState(); } class _GreenNavBarPageState extends State<GreenNavBarPage> with WidgetsBindingObserver { @override void initState() { super.initState(); // 添加观察者 WidgetsBinding.instance.addObserver(this); // 初始化时设置绿色 SystemNavBarHelper.setGreenNavBar(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { super.didChangeAppLifecycleState(state); // 当页面从后台回到前台时,重新设置绿色(避免被其他操作覆盖) if (state == AppLifecycleState.resumed) { SystemNavBarHelper.setGreenNavBar(); } } @override void dispose() { // 移除观察者 WidgetsBinding.instance.removeObserver(this); // 只有当页面被彻底销毁时,才恢复白色 SystemNavBarHelper.setWhiteNavBar(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text("绿色导航栏页面")), body: const Center(child: Text("这是带有绿色导航栏的页面")), ); } }
其他需要白色导航栏的页面,如果默认就是白色,只需要在必要的地方调用SystemNavBarHelper.setWhiteNavBar()即可。
方案二:自定义路由观察者(更适合多页面场景)
如果你的App有很多页面需要不同的导航栏颜色,用路由观察者会更省心——它能自动监听页面的push和pop动作,统一处理颜色切换:
先自定义一个路由观察者类:
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; class NavBarRouteObserver extends NavigatorObserver { @override void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) { super.didPush(route, previousRoute); // 根据当前页面的名称设置对应颜色 _setNavBarColor(route.settings.name); } @override void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) { super.didPop(route, previousRoute); // 当返回上一页时,根据上一页的名称设置颜色 _setNavBarColor(previousRoute?.settings.name); } void _setNavBarColor(String? routeName) { if (routeName == "/green-page") { SystemNavBarHelper.setGreenNavBar(); } else { // 默认设置为白色 SystemNavBarHelper.setWhiteNavBar(); } } }
然后在MaterialApp中注册这个观察者:
void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: '导航栏颜色示例', // 注册路由观察者 navigatorObservers: [NavBarRouteObserver()], initialRoute: "/", routes: { "/": (context) => const WhiteNavBarPage(), "/green-page": (context) => const GreenNavBarPage(), }, ); } }
这种方式不需要在每个页面里写颜色设置的代码,所有的颜色切换逻辑都集中在观察者里,维护起来更方便。
小提醒
- 如果你用的是
Navigator.push而不是命名路由,可以通过route.settings.arguments传递页面的导航栏颜色标识,在观察者中判断。 - 测试的时候要注意页面跳转的各种场景:push、pop、后台切前台,确保颜色都能正确切换。
内容来源于stack exchange
相关产品推荐
相关产品推荐

