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

如何在Flutter中实现类似Instagram的浮动消息输入框?

实现类似Instagram的浮动消息输入框(Flutter)

核心思路

通过Flutter的MediaQuery监听键盘高度变化,结合Stack+AnimatedPositioned或Scaffold的bottomSheet组件,就能实现输入框随键盘上浮的浮动效果,还可以添加滚动交互优化体验。

具体实现方案

方案1:自定义动画控制(灵活度高)

适合需要精准控制动画细节的场景:

class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _inputController = TextEditingController();
  double _keyboardHeight = 0;

  @override
  void initState() {
    super.initState();
    // 监听键盘高度变化
    WidgetsBinding.instance.addPostFrameCallback((_) {
      MediaQuery.of(context).viewInsets.addListener(_updateKeyboardHeight);
    });
  }

  void _updateKeyboardHeight() {
    setState(() {
      _keyboardHeight = MediaQuery.of(context).viewInsets.bottom;
    });
  }

  @override
  void dispose() {
    MediaQuery.of(context).viewInsets.removeListener(_updateKeyboardHeight);
    _inputController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('聊天')),
      body: Stack(
        children: [
          // 聊天消息列表
          ListView.builder(
            padding: const EdgeInsets.only(bottom: 80),
            itemCount: 30,
            itemBuilder: (context, index) => Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
              child: Text('消息内容 $index'),
            ),
          ),
          // 浮动输入框
          AnimatedPositioned(
            duration: const Duration(milliseconds: 220),
            left: 16,
            right: 16,
            bottom: _keyboardHeight + 16,
            child: Container(
              padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(28),
                boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.2), blurRadius: 6)],
              ),
              child: Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: _inputController,
                      decoration: const InputDecoration(
                        hintText: '输入消息...',
                        border: InputBorder.none,
                        contentPadding: EdgeInsets.symmetric(horizontal: 12),
                      ),
                    ),
                  ),
                  IconButton(
                    icon: const Icon(Icons.send, color: Colors.blueAccent),
                    onPressed: () {
                      // 发送消息逻辑
                    },
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

方案2:用bottomSheet快速实现(简化开发)

如果不需要复杂动画,Scaffold的bottomSheet会自动适配键盘高度:

Scaffold(
  appBar: AppBar(title: const Text('聊天')),
  body: ListView.builder(
    itemCount: 30,
    itemBuilder: (context, index) => Padding(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: Text('消息内容 $index'),
    ),
  ),
  bottomSheet: Container(
    padding: EdgeInsets.only(
      bottom: MediaQuery.of(context).viewInsets.bottom,
      left: 16,
      right: 16,
      top: 8,
    ),
    color: Colors.white,
    child: Row(
      children: [
        Expanded(
          child: TextField(
            decoration: InputDecoration(
              hintText: '输入消息...',
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(28),
                borderSide: BorderSide.none,
              ),
              filled: true,
              fillColor: Colors.grey.shade100,
              contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
            ),
          ),
        ),
        const SizedBox(width: 8),
        Container(
          decoration: const BoxDecoration(
            color: Colors.blueAccent,
            shape: BoxShape.circle,
          ),
          child: IconButton(
            icon: const Icon(Icons.send, color: Colors.white),
            onPressed: () {},
          ),
        ),
      ],
    ),
  ),
)

额外优化:滚动收起键盘

添加滚动监听,实现列表向上滚动时自动收起键盘,还原Instagram的交互逻辑:

final ScrollController _scrollController = ScrollController();

@override
void initState() {
  super.initState();
  _scrollController.addListener(() {
    if (_scrollController.position.userScrollDirection == ScrollDirection.forward) {
      FocusScope.of(context).unfocus();
    }
  });
}

// 给ListView绑定controller
ListView.builder(
  controller: _scrollController,
  // ...其他属性
)

关键细节说明

  • MediaQuery.viewInsets.bottom:获取当前键盘的高度,是实现输入框随键盘上浮的核心参数
  • AnimatedPositioned:让输入框的位置变化带有平滑过渡动画,避免生硬跳转
  • bottomSheet:Flutter内置组件,自动处理键盘弹出时的布局调整,减少自定义代码量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 07:42:21