Flutter基于auto_route嵌套导航时,模态底部弹窗打开后状态栏未变暗的问题求助
Flutter基于auto_route嵌套导航时,模态底部弹窗打开后状态栏未变暗的问题求助
我之前用auto_route做嵌套导航时,也碰到过一模一样的问题——非嵌套导航下打开showModalBottomSheet,状态栏会自动变暗,但切换到嵌套导航后这个效果就没了。折腾了好一阵才搞明白原因,给你分享下解决思路和办法:
问题根源
在嵌套导航结构里,你调用showModalBottomSheet时传入的context大概率是嵌套导航器的context,而非根导航器的context。Flutter的状态栏全局UI效果(比如变暗遮罩)是由根导航器层级负责管理的,嵌套导航器的context属于子层级,系统没办法识别要对全局状态栏应用效果,所以就出现了状态栏保持原色的情况。
解决办法(按推荐优先级排序)
1. 使用根导航器的Context调用Bottom Sheet
这是最直接也最符合Flutter设计的方案——获取根导航器的context,用它来启动showModalBottomSheet,让系统正确识别要应用全局状态栏效果。
修改你的代码只需要两步:
- 在调用
showModalBottomSheet前,获取根导航器的context - 把原来的
context参数替换成根context
修改后的完整代码:
void showCustomBottomSheet(BuildContext context) { // 获取根导航器的Context final rootContext = Navigator.of(context, rootNavigator: true).context; showModalBottomSheet( context: rootContext, // 替换为根Context shape: RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), backgroundColor: Colors.white, isScrollControlled: true, builder: (context) { return Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, top: 16, left: 16, right: 16, ), child: Wrap( children: [ Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(2), ), ), ), SizedBox(height: 16), Text( 'Bir seçenek seç', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), ListTile( leading: Icon(Icons.share), title: Text('Paylaş'), onTap: () { Navigator.pop(context, 'paylas'); }, ), ListTile( leading: Icon(Icons.link), title: Text('Link kopyala'), onTap: () { Navigator.pop(context, 'link'); }, ), ListTile( leading: Icon(Icons.delete), title: Text('Sil'), onTap: () { Navigator.pop(context, 'sil'); }, ), ], ), ); }, ).then((value) { if (value != null) { print("Seçilen: $value"); } }); }
如果上面的方法获取根context失败(比如某些复杂嵌套场景),可以用全局Key绑定根导航器:
- 先在全局定义根导航Key:
final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>(); - 在
MaterialApp.router中绑定这个Key:MaterialApp.router( routerDelegate: AutoRouterDelegate( _appRouter, navigatorKey: rootNavigatorKey, // 绑定根导航Key ), routeInformationParser: _appRouter.defaultRouteParser(), ) - 最后在Bottom Sheet中使用这个Key的context:
showModalBottomSheet( context: rootNavigatorKey.currentContext!, // 其他参数不变 )
2. 手动控制状态栏样式(备选方案)
如果根context的方法不生效,还可以手动控制状态栏的颜色,在打开Bottom Sheet时设置为你需要的变暗效果,关闭时恢复原样式:
import 'package:flutter/services.dart'; // 记得导入这个包 void showCustomBottomSheet(BuildContext context) { // 保存当前状态栏样式,用于后续恢复 final originalStatusStyle = SystemChrome.latestStyle; // 打开Bottom Sheet时,设置状态栏为变暗效果 SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( statusBarColor: Colors.deepPurple.withOpacity(0.7), // 替换成你需要的变暗颜色 statusBarIconBrightness: Brightness.light, // 如果状态栏图标需要变亮,就加这个 )); showModalBottomSheet( // 原有的参数不变 ).then((value) { // 关闭Bottom Sheet后,恢复原来的状态栏样式 if (originalStatusStyle != null) { SystemChrome.setSystemUIOverlayStyle(originalStatusStyle); } if (value != null) { print("Seçilen: $value"); } }); }
这个方案要注意:如果同时打开多个弹窗,需要小心样式覆盖的问题,所以优先推荐第一种方案。
内容来源于stack exchange
相关产品推荐
相关产品推荐

