Flutter实现键盘弹出时隐藏Bottom Sheet的方法求助
Flutter 实现键盘弹出时隐藏BottomSheet方案
核心思路
通过状态变量控制BottomSheet的显示/隐藏,结合焦点监听或全局键盘状态监听,在输入框获焦、键盘弹出时隐藏BottomSheet,失去焦点、键盘收起时恢复显示,同时保留BottomSheet内动态可滚动列表的特性。
具体实现步骤
- 转为StatefulWidget维护状态
在页面的State类中添加布尔变量,用于控制BottomSheet的显示状态:
bool _showBottomSheet = true;
- 动态控制BottomSheet显示
修改Scaffold的bottomSheet属性,根据状态变量返回对应组件或null:
bottomSheet: _showBottomSheet ? Container( // 你原有的BottomSheet布局代码 decoration: BoxDecoration( color: mainColor, borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), child: Container( margin: const EdgeInsetsDirectional.only(start: 2, end: 2, top: 2), padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(14), topRight: Radius.circular(14), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ // 替换为你的动态可滚动商品列表 Expanded( child: ListView.builder( shrinkWrap: true, itemCount: 10, itemBuilder: (context, index) => Text("商品 $index"), ), ), ], ), ), ) : null,
- 监听输入框焦点变化(单输入场景)
给输入框包裹FocusListener,在焦点切换时更新状态:
FocusListener( onFocusChange: (hasFocus) { setState(() { _showBottomSheet = !hasFocus; }); }, child: TextField( decoration: InputDecoration(hintText: "输入内容"), ), )
- 全局键盘状态监听(多输入场景)
通过WidgetsBindingObserver监听系统键盘状态,适合页面存在多个输入框的场景:
- 在State类混入
WidgetsBindingObserver:
class _YourPageState extends State<YourPage> with WidgetsBindingObserver {
- 注册/取消监听:
@override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); }
- 重写方法判断键盘状态:
@override void didChangeMetrics() { super.didChangeMetrics(); final bottomInset = WidgetsBinding.instance.window.viewInsets.bottom; setState(() { _showBottomSheet = bottomInset == 0; }); }
完整代码示例
class YourPage extends StatefulWidget { @override _YourPageState createState() => _YourPageState(); } class _YourPageState extends State<YourPage> with WidgetsBindingObserver { bool _showBottomSheet = true; @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeMetrics() { super.didChangeMetrics(); final bottomInset = WidgetsBinding.instance.window.viewInsets.bottom; setState(() { _showBottomSheet = bottomInset == 0; }); } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: false, backgroundColor: Colors.white, bottomSheet: _showBottomSheet ? Container( decoration: BoxDecoration( color: mainColor, borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), child: Container( margin: const EdgeInsetsDirectional.only(start: 2, end: 2, top: 2), padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.only( topLeft: Radius.circular(14), topRight: Radius.circular(14), ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Expanded( child: ListView.builder( shrinkWrap: true, itemCount: 10, itemBuilder: (context, index) => Text("商品 $index"), ), ), ], ), ), ) : null, body: Padding( padding: EdgeInsets.only(left: 12, top: 5, right: 12), child: SingleChildScrollView( child: Container( height: ScreenSizeConfig.screenHeight, child: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( decoration: InputDecoration(hintText: "输入内容"), ), // 其他页面组件 ], ), ), ), ), ); } }
替代方案说明
若需更复杂的BottomSheet交互,可使用PersistentBottomSheet:通过ScaffoldState.showBottomSheet创建并获取控制器,在键盘弹出时调用controller.close(),键盘收起时重新调用showBottomSheet打开,核心逻辑依然是通过状态触发显示/隐藏操作。
内容的提问来源于stack exchange,提问作者La Pyae
相关产品推荐
相关产品推荐

