Flutter中实现TextFormField聚焦时显示历史邮箱输入建议
Flutter 实现带历史邮箱建议的 TextFormField
核心思路是通过持久化存储历史邮箱+官方Autocomplete组件来实现,具体步骤和代码如下:
1. 添加依赖
首先在pubspec.yaml中引入shared_preferences用于持久化存储历史邮箱:
dependencies: flutter: sdk: flutter shared_preferences: ^2.2.2
2. 封装历史邮箱的存储与读取方法
写两个工具方法,负责从本地存储获取历史邮箱,以及将新邮箱去重保存:
import 'package:shared_preferences/shared_preferences.dart'; // 获取本地存储的历史邮箱列表 Future<List<String>> getHistoryEmails() async { final prefs = await SharedPreferences.getInstance(); return prefs.getStringList('email_history') ?? []; } // 将邮箱保存到历史(自动去重,限制最多10条) Future<void> saveEmailToHistory(String email) async { final prefs = await SharedPreferences.getInstance(); var history = await getHistoryEmails(); // 去重并把最新的邮箱移到最前面 history.remove(email); history.insert(0, email); // 限制历史数量,避免列表过长 if (history.length > 10) { history = history.take(10).toList(); } await prefs.setStringList('email_history', history); }
3. 实现带历史建议的邮箱输入组件
利用Flutter官方的Autocomplete组件,结合TextFormField实现需求:
import 'package:flutter/material.dart'; class EmailInputField extends StatefulWidget { const EmailInputField({super.key}); @override State<EmailInputField> createState() => _EmailInputFieldState(); } class _EmailInputFieldState extends State<EmailInputField> { late Future<List<String>> _historyEmailsFuture; @override void initState() { super.initState(); // 初始化时获取历史邮箱 _historyEmailsFuture = getHistoryEmails(); } @override Widget build(BuildContext context) { return FutureBuilder<List<String>>( future: _historyEmailsFuture, builder: (context, snapshot) { final historyEmails = snapshot.data ?? []; return Autocomplete<String>( // 构建建议列表:输入为空时展示所有历史,输入内容时过滤匹配项 optionsBuilder: (TextEditingValue textEditingValue) { if (textEditingValue.text.isEmpty) { return historyEmails; } return historyEmails.where((email) => email.toLowerCase().contains(textEditingValue.text.toLowerCase()) ).toList(); }, // 自定义输入框为TextFormField fieldViewBuilder: (context, controller, focusNode, onSubmitted) { return TextFormField( controller: controller, focusNode: focusNode, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration( labelText: '邮箱', border: OutlineInputBorder(), ), // 邮箱格式校验 validator: (value) { if (value == null || value.isEmpty || !RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return '请输入有效的邮箱'; } return null; }, // 提交时保存邮箱到历史 onFieldSubmitted: (value) { onSubmitted(); if (value.isNotEmpty) { saveEmailToHistory(value); // 更新历史列表,确保下次打开能看到最新记录 setState(() { _historyEmailsFuture = getHistoryEmails(); }); } }, ); }, // 选中建议后的逻辑:填充到输入框 onSelected: (selectedEmail) { Autocomplete.of(context)?.textEditingController.text = selectedEmail; }, // 自定义建议列表的样式 optionsViewBuilder: (context, onSelected, options) { return Align( alignment: Alignment.topLeft, child: Material( elevation: 4, child: SizedBox( width: MediaQuery.of(context).size.width - 40, child: ListView.builder( padding: EdgeInsets.zero, shrinkWrap: true, itemCount: options.length, itemBuilder: (context, index) { final email = options.elementAt(index); return ListTile( title: Text(email), onTap: () => onSelected(email), ); }, ), ), ), ); }, ); }, ); } }
关键说明
- Autocomplete组件:官方提供的组件,自带焦点监听、建议展示逻辑,无需手动处理弹窗的显示/隐藏。
- 持久化存储:用
SharedPreferences保证APP重启后历史邮箱不会丢失。 - 去重与排序:保存时自动去重,并将最新邮箱移到列表最顶部,提升用户体验。
- 灵活过滤:输入内容时会自动过滤出包含输入文本的历史邮箱,输入为空(获取焦点时)展示全部历史。
内容的提问来源于stack exchange,提问作者VISHNU PRABHAKARAN
相关产品推荐
相关产品推荐

