如何在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
相关产品推荐
相关产品推荐

