Flutter Autocomplete如何取消默认选中第一项并将选中项设为null?
解决Flutter Autocomplete自动选中第一项的问题
要实现下拉列表无默认选中项、仅允许手动点击选择,且回车不触发选中,可以通过自定义optionsViewBuilder和控制TextField的键盘事件来实现,具体方案如下:
核心实现步骤
- 用
ValueNotifier跟踪选中索引,初始设为-1(表示无选中项) - 自定义选项视图,仅在手动点击时触发选中状态变化
- 拦截输入框的回车事件,阻止默认的自动选中逻辑
完整代码示例
import 'package:flutter/material.dart'; void main() => runApp(const AutocompleteExampleApp()); class AutocompleteExampleApp extends StatelessWidget { const AutocompleteExampleApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Autocomplete无默认选中示例')), body: const Center( child: _CustomAutocomplete(), ), ), ); } } class _CustomAutocomplete extends StatefulWidget { const _CustomAutocomplete(); @override State<_CustomAutocomplete> createState() => _CustomAutocompleteState(); } class _CustomAutocompleteState extends State<_CustomAutocomplete> { final TextEditingController _textEditingController = TextEditingController(); final ValueNotifier<int> _selectedIndex = ValueNotifier(-1); // 初始无选中项 static const List<String> _options = <String>[ 'aardvark', 'bobcat', 'chameleon', 'dolphin', 'elephant', 'flamingo', ]; @override void dispose() { _textEditingController.dispose(); _selectedIndex.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Autocomplete<String>( controller: _textEditingController, optionsBuilder: (TextEditingValue textEditingValue) { if (textEditingValue.text.isEmpty) { return const Iterable<String>.empty(); } return _options.where((String option) { return option.contains(textEditingValue.text.toLowerCase()); }); }, // 自定义选项视图,控制选中逻辑 optionsViewBuilder: (BuildContext context, AutocompleteOnSelected<String> onSelected, Iterable<String> options) { return Align( alignment: Alignment.topLeft, child: Material( elevation: 4.0, child: SizedBox( height: 200.0, child: ListView.builder( padding: const EdgeInsets.all(8.0), itemCount: options.length, itemBuilder: (BuildContext context, int index) { final String option = options.elementAt(index); return ValueListenableBuilder<int>( valueListenable: _selectedIndex, builder: (context, selectedIdx, child) { return InkWell( onTap: () { onSelected(option); _selectedIndex.value = -1; // 选中后重置为无选中状态 _textEditingController.text = option; }, child: Container( color: selectedIdx == index ? Theme.of(context).focusColor : Colors.transparent, padding: const EdgeInsets.all(16.0), child: Text(option), ), ); }, ); }, ), ), ), ); }, // 自定义输入框,拦截回车事件 fieldViewBuilder: (BuildContext context, TextEditingController textEditingController, FocusNode focusNode, VoidCallback onFieldSubmitted) { return TextField( controller: textEditingController, focusNode: focusNode, onSubmitted: (String value) { // 不执行任何操作,阻止默认回车选中逻辑 }, decoration: const InputDecoration( hintText: '输入字符搜索...', border: OutlineInputBorder(), ), ); }, onSelected: (String selection) { debugPrint('选中了: $selection'); }, ); } }
关键细节说明
- 选中状态控制:通过
ValueNotifier<int>管理选中索引,初始值-1确保没有默认选中项,只有手动点击选项时才更新状态并触发选中回调。 - 选项视图自定义:用
ValueListenableBuilder监听选中索引变化,动态切换选项的高亮样式,避免自动选中逻辑。 - 回车事件拦截:在输入框的
onSubmitted回调中不做任何处理,彻底阻止回车自动选中第一项的默认行为。
设置完成后,输入字符时下拉列表正常展示匹配选项,但不会自动选中任何项,仅支持手动点击选择,按下回车也不会触发选中动作。
内容的提问来源于stack exchange,提问作者ERG
相关产品推荐
相关产品推荐

