在很多 App 中,当用户输入搜索内容时,往往会自动匹配一些候选搜索内容,以便让用户快速完成搜索内容的输入。同时,也可以在候选的搜索内容中根据用户偏好“加塞”广告,提高成交转化率。比如在淘宝搜索“苹果”这个词时,就会出现苹果相关的候选选项。类似这样的功能就需要用到输入内容的自动填充。
这种功能可以自己去写两个独立的组件,比如一个搜索框,一个候选内容弹层,通过内容联动来实现。不过,Flutter 中其实有自带的组件,叫做 AutoComplete。
class Autocomplete<T extends Object> extends StatelessWidget { const Autocomplete({ super.key, required this.optionsBuilder, this.displayStringForOption = RawAutocomplete.defaultStringForOption, this.fieldViewBuilder = _defaultFieldViewBuilder, this.onSelected, this.optionsMaxHeight = 200.0, this.optionsViewBuilder, this.initialValue, }); //……其中泛型指的是候选内容对象的类型,最简单的就是 String 类型,但是我们后台返回的可能会是一个完整的对象,这个时候我们就可以定义为后台对象对应的实体类。具体的参数说明如下:
initialValue:初始值,比如根据用户近期浏览记录推荐一个候选的初始值。
class AutoCompleteDemo extends StatefulWidget { const AutoCompleteDemo({super.key}); @override // 堆代码 duidaima.com // ignore: library_private_types_in_public_api _AutoCompleteDemoState createState() => _AutoCompleteDemoState(); } class _AutoCompleteDemoState extends State<AutoCompleteDemo> { final List<Country> countries = [ Country(id: 1, name: '中国'), Country(id: 2, name: '美国'), Country(id: 3, name: '印度'), Country(id: 4, name: '俄罗斯'), Country(id: 5, name: '英国'), Country(id: 6, name: '巴西'), Country(id: 7, name: '法国'), Country(id: 8, name: '德国'), ]; var selectedCountry = ''; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('AutoComplete Demo'), ), body: Center( child: Autocomplete<Country>( optionsBuilder: (TextEditingValue textEditingValue) { return Future.delayed(const Duration(milliseconds: 2000), () { return countries .where( (country) => country.name.contains(textEditingValue.text)) .toList(); }); }, onSelected: (Country country) { selectedCountry = country.name; }, fieldViewBuilder: (BuildContext context, TextEditingController textEditingController, FocusNode focusNode, VoidCallback onFieldSubmitted) { return TextField( controller: textEditingController, focusNode: focusNode, onChanged: (text) { selectedCountry = text; }, decoration: const InputDecoration( labelText: '国家', ), ); }, displayStringForOption: (Country country) => '[${country.id}] ${country.name}', initialValue: TextEditingValue(text: selectedCountry), ), ), ); } } class Country { final int id; final String name; Country({required this.id, required this.name}); }这里我们使用了Country这个类作为AutoComplete的泛型参数,这样就可以支持对Country列表数据进行处理了。具体的逻辑说明如下: