You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 17:48:20