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

Flutter如何让悬浮操作按钮固定在底部导航栏不随键盘上浮

问题原因

FAB随键盘上浮是因为Scaffold默认resizeToAvoidBottomInset属性为true,键盘弹出时会重新调整页面布局尺寸,FAB作为Scaffold的浮动组件会同步上移。以下是两种可直接落地的解决方案:


方案1:固定FAB位置,不随键盘上浮

只需要修改Scaffold的配置,同时适配输入框的显示逻辑即可:

  1. 给Scaffold添加resizeToAvoidBottomInset: false,禁止页面随键盘弹出调整布局
  2. 将原本的Column类型body嵌套进SingleChildScrollView,避免输入框聚焦后被键盘遮挡

修改后的核心代码如下:

Scaffold(
  // 新增这一行配置
  resizeToAvoidBottomInset: false,
  // 嵌套SingleChildScrollView
  body: SingleChildScrollView(
    child: Column(children: [
      // 原有搜索框代码保持不变
      Padding(
        padding: const EdgeInsets.only(left: 16, right: 16,top: 20),
        child: Container(
          height: 40,
          decoration: BoxDecoration(
            color: Color(0xffEBEDF4),
            borderRadius: BorderRadius.circular(25),
          ),
          child: Row(
            children: [
              Expanded(
                flex: 2,
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: TextFormField(
                    keyboardType: TextInputType.text,
                    inputFormatters: [UpperCaseTextFormatter()],
                    style: const TextStyle(
                      color: Colors.white,
                      fontSize: 15,
                      fontFamily: 'PoppinsRegular',
                    ),
                    decoration: InputDecoration(
                      hintText: 'Search...',
                      hintStyle: theme.textTheme.caption!.copyWith(
                        color: const Color(0xffEBEDF4),
                      ),
                      isDense: true,
                      contentPadding: const EdgeInsets.fromLTRB(10, 10, 10, 0),
                      fillColor:const Color(0xffEBEDF4),
                      filled: true,
                      border: InputBorder.none,
                      focusedBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(8.0),
                        borderSide: const BorderSide(
                          color: Color(0xffEBEDF4),
                        ),
                      ),
                      enabledBorder: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(8.0),
                        borderSide:const BorderSide(
                          color: Color(0xffEBEDF4),
                          width: 1.0,
                        ),
                      ),
                    ),
                  ),
                ),
              ),
              IconButton(
                  onPressed: () {
                    searchStuff();
                  },
                  icon:const Icon(Icons.search)),
            ],
          ),
        ),
      ),
    ]),
  ),
  // 原有FAB和底部导航栏配置保持不变
  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      print('Test bottom nav bar');
    },
    child: const Icon(Icons.add),
  ),
  bottomNavigationBar: BottomNavigationBar(
    items: const <BottomNavigationBarItem>[
      BottomNavigationBarItem(
        icon: Icon(Icons.call),
        label: 'Calls',
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.chat),
        label: 'Chats',
      ),
    ],
    currentIndex: _selectedIndex,
    onTap: _onItemTapped,
  ),
)

方案2:将FAB嵌入底部导航栏,形成一体化效果

使用BottomAppBar替代原有直接挂载的BottomNavigationBar,自带适配FAB的凹槽效果,FAB会直接嵌在底部导航栏中完全固定:

Scaffold(
  resizeToAvoidBottomInset: false,
  body: SingleChildScrollView(
    child: Column(children: [
      // 原有搜索框代码保持不变
    ]),
  ),
  floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
  floatingActionButton: FloatingActionButton(
    onPressed: () {
      print('Test bottom nav bar');
    },
    child: const Icon(Icons.add),
  ),
  // 替换原有底部导航栏为BottomAppBar嵌套BottomNavigationBar
  bottomNavigationBar: BottomAppBar(
    shape: const CircularNotchedRectangle(), // 生成适配FAB的圆形凹槽
    notchMargin: 6, // 凹槽和FAB之间的留白间距
    elevation: 8,
    child: BottomNavigationBar(
      backgroundColor: Colors.transparent, // 必须设为透明,否则会挡住凹槽效果
      elevation: 0,
      items: const <BottomNavigationBarItem>[
        BottomNavigationBarItem(
          icon: Icon(Icons.call),
          label: 'Calls',
        ),
        BottomNavigationBarItem(
          icon: Icon(Icons.chat),
          label: 'Chats',
        ),
      ],
      currentIndex: _selectedIndex,
      onTap: _onItemTapped,
    ),
  ),
)

额外适配方案(保留页面自动调整能力)

如果不希望禁用resizeToAvoidBottomInset(保留输入框不被键盘遮挡的默认适配),可以放弃Scaffold自带的FAB参数,手动用Stack定位FAB在页面底部:

Scaffold(
  // 保留默认的resizeToAvoidBottomInset: true
  body: Stack(
    children: [
      // 原有页面body代码保持不变
      Column(
        children: [
          // 搜索框等原有内容
        ],
      ),
      // 手动定位FAB在底部居中
      Positioned(
        bottom: 20,
        left: 0,
        right: 0,
        child: Center(
          child: FloatingActionButton(
            onPressed: () {
              print('Test bottom nav bar');
            },
            child: const Icon(Icons.add),
          ),
        ),
      )
    ],
  ),
  // 原有BottomNavigationBar代码不变,删除原来的floatingActionButton相关配置
  bottomNavigationBar: BottomNavigationBar(
    items: const <BottomNavigationBarItem>[
      BottomNavigationBarItem(
        icon: Icon(Icons.call),
        label: 'Calls',
      ),
      BottomNavigationBarItem(
        icon: Icon(Icons.chat),
        label: 'Chats',
      ),
    ],
    currentIndex: _selectedIndex,
    onTap: _onItemTapped,
  ),
)

内容的提问来源于stack exchange,提问作者Kevnlan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:24:07