You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

问题原因

  1. 初始build执行时,键盘尚未完全弹出,此时viewInsets.bottom值为0
  2. 键盘弹出后,未触发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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:20:58