Flutter中如何正确获取键盘高度并实现内容在剩余空间居中?
如何正确获取Flutter键盘高度并实现内容居中?
我尝试使用double keyboardHeight = MediaQuery.of(context).viewInsets.bottom;获取键盘高度,但该方法无效,控制台输出显示keyboardHeight始终为0.0。
测试代码
Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('Keyboard test')), body: Builder( builder: (context) { double screenHeight = MediaQuery.of(context).size.height; double keyboardHeight = MediaQuery.of(context).viewInsets.bottom; double availableHeight = screenHeight - keyboardHeight; print('screenHeight: $screenHeight'); print('keyboardHeight: $keyboardHeight'); print('availableHeight: $availableHeight'); return SingleChildScrollView( child: SizedBox( height: availableHeight, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( autofocus: true, onSubmitted: (value) {}, keyboardType: TextInputType.number, ), ], ), ), ); }, ), ); }
控制台输出
I/flutter (29239): screenHeight: 672.0 I/flutter (29239): keyboardHeight: 0.0 I/flutter (29239): availableHeight: 672.0
问题原因
- 初始
build执行时,键盘尚未完全弹出,此时viewInsets.bottom值为0 - 键盘弹出后,未触发Widget重建以获取更新后的
viewInsets数值
解决方案
方案一:使用WidgetsBindingObserver监听键盘状态变化
这是最可靠的方式,能实时监听键盘弹出、收起的高度变化:
class KeyboardTestPage extends StatefulWidget { @override _KeyboardTestPageState createState() => _KeyboardTestPageState(); } class _KeyboardTestPageState extends State<KeyboardTestPage> with WidgetsBindingObserver { double _keyboardHeight = 0.0; @override void initState() { super.initState(); // 注册窗口 metrics 监听 WidgetsBinding.instance.addObserver(this); } @override void dispose() { // 取消监听,避免内存泄漏 WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeMetrics() { super.didChangeMetrics(); // 获取最新的键盘高度并更新状态 final bottomInset = MediaQuery.of(context).viewInsets.bottom; setState(() { _keyboardHeight = bottomInset; }); } @override Widget build(BuildContext context) { double screenHeight = MediaQuery.of(context).size.height; double availableHeight = screenHeight - _keyboardHeight; print('screenHeight: $screenHeight'); print('keyboardHeight: $_keyboardHeight'); print('availableHeight: $availableHeight'); return Scaffold( appBar: AppBar(title: Text('Keyboard test')), body: SingleChildScrollView( child: SizedBox( height: availableHeight, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( autofocus: true, onSubmitted: (value) {}, keyboardType: TextInputType.number, ), ], ), ), ), ); } }
方案二:依赖MediaQuery自动触发重建
直接在build方法中获取viewInsets.bottom,确保Widget布局依赖该值,从而在键盘状态变化时自动重建:
class KeyboardTestPage extends StatefulWidget { @override _KeyboardTestPageState createState() => _KeyboardTestPageState(); } class _KeyboardTestPageState extends State<KeyboardTestPage> { @override void initState() { super.initState(); // 等待初始渲染完成后,触发首次更新获取键盘高度 WidgetsBinding.instance.addPostFrameCallback((_) { setState(() {}); }); } @override Widget build(BuildContext context) { double screenHeight = MediaQuery.of(context).size.height; double keyboardHeight = MediaQuery.of(context).viewInsets.bottom; double availableHeight = screenHeight - keyboardHeight; print('screenHeight: $screenHeight'); print('keyboardHeight: $keyboardHeight'); print('availableHeight: $availableHeight'); return Scaffold( appBar: AppBar(title: Text('Keyboard test')), body: SingleChildScrollView( child: SizedBox( height: availableHeight, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ TextField( autofocus: true, onSubmitted: (value) {}, keyboardType: TextInputType.number, ), ], ), ), ), ); } }
注意事项
SingleChildScrollView用于避免键盘弹出时内容被遮挡,同时配合SizedBox设置可用高度,确保Column能在剩余空间内居中布局- 方案一的监听方式能处理键盘弹出、收起的所有场景,推荐作为首选方案
内容的提问来源于stack exchange,提问作者rozerro
相关产品推荐
相关产品推荐

