Flutter开发中如何实现TextField光标悬浮在键盘上方?
解决方案
你之前的方案不生效,核心是没有利用系统自带的键盘适配逻辑,手动计算偏移量容易出现context未同步更新的问题,推荐使用以下两种方案:
方案1:使用Scaffold自带底部属性适配(推荐)
这个方案无需手动计算键盘偏移,Scaffold会自动处理键盘弹出时的页面位移,输入框会自动悬浮在键盘上方:
Scaffold( // 保持默认true即可,不要手动设为false resizeToAvoidBottomInset: true, body: Stack( children: [ const Positioned.fill( child: Image( image: AssetImage('assets/images/background.png'), repeat: ImageRepeat.repeat, ), ), ListView.separated( separatorBuilder: (_, __) => const SizedBox(height: 8), itemCount: 5, reverse: true, // 可自行调整边距,Scaffold会自动添加底部边距避免内容被输入框遮挡 padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), itemBuilder: (_, index) { // 替换为你自己的消息项组件 return const SizedBox(); }, ), ], ), // 输入框放在bottomNavigationBar中,系统会自动适配键盘高度 bottomNavigationBar: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, ), // 适配全面屏底部安全区 padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), child: Row( children: [ IconButton( onPressed: () {}, icon: const Icon( Icons.attachment_rounded, color: kIconKeyboardChatColor, ), ), Expanded( child: TextField( decoration: const InputDecoration( enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, hintText: 'Write a message...', contentPadding: EdgeInsets.symmetric(vertical: 12, horizontal: 8), ), keyboardType: TextInputType.multiline, textInputAction: TextInputAction.newline, // 适配多行输入,可自行调整最大行数 minLines: 1, maxLines: 5, ), ), // 可按需添加发送按钮等组件 ], ), ), )
方案2:保留原Stack结构的修改方法
如果一定要用原来的Stack+Positioned的结构,需要修改两处:
- 确保包裹该Stack的Scaffold没有设置
resizeToAvoidBottomInset: false - 给Positioned的bottom值添加输入框高度的补偿,同时给ListView添加对应的边距避免内容被输入框遮挡:
// 先定义输入框的预设高度,你也可以用GlobalKey动态获取输入框高度 const double inputBarHeight = 56; Stack( children: [ const Positioned.fill( child: Image( image: AssetImage('assets/images/background.png'), repeat: ImageRepeat.repeat, ), ), ListView.separated( itemBuilder: (_, index) => const SizedBox(), separatorBuilder: (_, __) => const SizedBox(height: 8), itemCount: 5, reverse: true, // reverse为true时,padding.top对应列表底部的边距,用来避开输入框 padding: EdgeInsets.only(top: inputBarHeight + MediaQuery.of(context).padding.bottom + 12), ), Positioned( // 偏移量=键盘高度+底部安全区高度 bottom: MediaQuery.of(context).viewInsets.bottom + MediaQuery.of(context).padding.bottom, left: 0, right: 0, height: inputBarHeight, child: Container( decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, ), child: Row( children: [ IconButton( onPressed: () {}, icon: const Icon( Icons.attachment_rounded, color: kIconKeyboardChatColor, ), ), const Expanded( child: TextField( decoration: InputDecoration( enabledBorder: InputBorder.none, focusedBorder: InputBorder.none, hintText: 'Write a message...', ), keyboardType: TextInputType.multiline, textInputAction: TextInputAction.newline, minLines: 1, maxLines: 5, ), ), ], ), ), ), ], )
如果修改后还是不生效,可以尝试将输入框组件单独抽为一个StatefulWidget,确保MediaQuery获取到的viewInsets是最新的同步值。
内容的提问来源于stack exchange,提问作者Fajra Risqulla
相关产品推荐
相关产品推荐

