Flutter中BottomSheet内ListView的TextField被键盘遮挡问题求助
解决BottomSheet内ListView的TextField被键盘遮挡问题
方案1:利用FocusNode+ScrollController精准滚动到聚焦项
核心思路是给每个TextField绑定FocusNode,监听焦点获取事件,一旦某个TextField获得焦点,就通过滚动控制将其移动到ListView的可见区域。如果item高度不固定,推荐用Scrollable.ensureVisible自动计算位置,适配性更强。
代码示例(适配任意item高度)
class SheetWithTextFieldList extends StatefulWidget { const SheetWithTextFieldList({super.key}); @override State<SheetWithTextFieldList> createState() => _SheetWithTextFieldListState(); } class _SheetWithTextFieldListState extends State<SheetWithTextFieldList> { final ScrollController _scrollController = ScrollController(); late List<FocusNode> _focusNodes; late List<GlobalKey> _itemKeys; @override void initState() { super.initState(); // 初始化对应数量的FocusNode和GlobalKey const itemCount = 15; _focusNodes = List.generate(itemCount, (_) => FocusNode()); _itemKeys = List.generate(itemCount, (_) => GlobalKey()); // 给每个FocusNode添加焦点监听 for (int i = 0; i < itemCount; i++) { _focusNodes[i].addListener(() { if (_focusNodes[i].hasFocus) { final itemContext = _itemKeys[i].currentContext; if (itemContext != null) { // 自动滚动到聚焦项,设置居中避免被键盘遮挡 Scrollable.ensureVisible( itemContext, duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, alignment: 0.5, ); } } }); } } @override void dispose() { _scrollController.dispose(); // 销毁所有FocusNode避免内存泄漏 for (final node in _focusNodes) { node.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Container( // 固定BottomSheet高度,避免被键盘顶满屏幕 height: MediaQuery.of(context).size.height * 0.7, padding: const EdgeInsets.all(16), child: ListView.builder( controller: _scrollController, itemCount: 15, itemBuilder: (context, index) { return Padding( key: _itemKeys[index], padding: const EdgeInsets.symmetric(vertical: 8), child: TextField( focusNode: _focusNodes[index], decoration: InputDecoration( hintText: '输入框 ${index + 1}', border: const OutlineInputBorder(), ), ), ); }, ), ); } }
为什么不能用resizeToAvoidBottomInset?
给BottomSheet嵌套Scaffold并设置resizeToAvoidBottomInset: true会让BottomSheet直接占据整个屏幕,完全破坏了BottomSheet的模态弹窗特性,因此这种方案不可行。
注意事项
- 必须在
dispose方法中销毁FocusNode和ScrollController,防止内存泄漏。 Scrollable.ensureVisible会自动适配item高度变化,比固定计算滚动位置更可靠。- 可通过调整
alignment参数控制滚动后的位置(0为顶部对齐,1为底部对齐,0.5为居中)。
内容的提问来源于stack exchange,提问作者Jacoo
相关产品推荐
相关产品推荐

