Flutter中如何让SnackBar显示在showModalBottomSheet上方
解决ShowModalBottomSheet内SnackBar显示位置问题
你遇到的问题是因为调用showSnackBar时使用了BottomSheet内部的context,导致SnackBar被挂载在弹窗的上下文层级中,从而显示在弹窗下方。以下两种方案可以解决这个问题:
方案一:使用外部上下文显示全局SnackBar
通过提前获取页面根上下文的ScaffoldMessenger,让SnackBar挂载在页面顶层,自然显示在BottomSheet上方:
// 先获取外部页面的ScaffoldMessenger实例 final outerScaffoldMessenger = ScaffoldMessenger.of(context); showModalBottomSheet( isScrollControlled: true, isDismissible: false, context: context, builder: (context) { return SafeArea( child: Stack( alignment: Alignment.topCenter, clipBehavior: Clip.none, children: [ Column( children: [ Container( padding: const EdgeInsets.symmetric( horizontal: 30, vertical: 0), child: Column(children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 50), child: TextField( controller: codeController, keyboardType: TextInputType.number, ), ), const SizedBox( height: 5, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 50), child: CustomButton( onTap: () async { if (codeController.text.length == 6) { try { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: codeController.text.trim()); await _auth .signInWithCredential(credential); Navigator.of(context) .pushNamedAndRemoveUntil( '/home', (Route<dynamic> route) => false); } catch (e) { // 使用外部的ScaffoldMessenger显示SnackBar outerScaffoldMessenger.showSnackBar( SnackBar( content: Column( mainAxisSize: MainAxisSize.min, children: const [ Text("Invalid verification code"), Text("Please enter correct verification code"), ], ), duration: const Duration(seconds: 2), ), ); } } }, text: "Continue", height: 50), ) ]), ) ], ) ], ), ); });
方案二:在BottomSheet内部自定义本地SnackBar
如果希望SnackBar完全属于弹窗的一部分,可以在弹窗的Stack中添加自定义的提示组件,通过状态控制显示隐藏:
showModalBottomSheet( isScrollControlled: true, isDismissible: false, context: context, builder: (context) { return StatefulBuilder( builder: (context, setState) { bool showErrorSnackBar = false; return SafeArea( child: Stack( alignment: Alignment.topCenter, clipBehavior: Clip.none, children: [ Column( children: [ // 预留SnackBar高度,避免主体内容被遮挡 if (showErrorSnackBar) const SizedBox(height: 60), Container( padding: const EdgeInsets.symmetric( horizontal: 30, vertical: 0), child: Column(children: [ Padding( padding: const EdgeInsets.symmetric(horizontal: 50), child: TextField( controller: codeController, keyboardType: TextInputType.number, ), ), const SizedBox( height: 5, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 50), child: CustomButton( onTap: () async { if (codeController.text.length == 6) { try { PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: verificationId, smsCode: codeController.text.trim()); await _auth .signInWithCredential(credential); Navigator.of(context) .pushNamedAndRemoveUntil( '/home', (Route<dynamic> route) => false); } catch (e) { // 显示自定义SnackBar setState(() { showErrorSnackBar = true; }); // 2秒后自动隐藏 Future.delayed(const Duration(seconds: 2), () { setState(() { showErrorSnackBar = false; }); }); } } }, text: "Continue", height: 50), ) ]), ) ], ), // 自定义错误提示组件,位于弹窗顶部 if (showErrorSnackBar) Positioned( top: -50, left: 20, right: 20, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: Colors.redAccent, borderRadius: BorderRadius.circular(8), ), child: Column( mainAxisSize: MainAxisSize.min, children: const [ Text("Invalid verification code", style: TextStyle(color: Colors.white)), Text("Please enter correct verification code", style: TextStyle(color: Colors.white, fontSize: 12)), ], ), ), ) ], ), ); }, ); });
关键说明
- 方案一的SnackBar属于全局提示,会显示在页面顶部,覆盖BottomSheet的上边缘,不会隐藏弹窗。
- 方案二的提示组件完全属于BottomSheet,位置可以自由调整,样式也能自定义,更贴合弹窗的整体设计。
内容的提问来源于stack exchange,提问作者Rokey Z
相关产品推荐
相关产品推荐

