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

如何在Flutter中实现Gmail风格的TextFormField选择控制效果

Flutter 实现 Gmail 式列表选择控制教程

效果对比

  • Flutter 默认选择控制效果:
    Flutter默认选择控制效果
  • 目标 Gmail 选择控制效果:
    Gmail选择控制效果

核心实现逻辑

无需引入第三方依赖,按照以下步骤即可快速实现该效果:

  • 状态管理:声明一个集合存储当前选中的列表项唯一标识,同时通过集合是否非空判断当前是否处于选择模式
    // 存储选中的item id,类型可以根据你自己的item主键调整
    Set<String> selectedIds = {};
    // 快捷判断是否进入选择模式
    bool get inSelectMode => selectedIds.isNotEmpty;
    
  • 列表项交互适配
    分两种模式处理交互:
    1. 非选择模式:点击列表项触发正常跳转/查看逻辑,长按列表项触发选择模式,同时把当前长按的项加入选中集合
    2. 选择模式:点击任意列表项切换该项目的选中状态,当所有选中项都被取消、集合为空时自动退出选择模式
      列表UI同步适配:选中项增加高亮背景,原头像位置替换为勾选/未勾选图标
  • 顶部导航栏动态切换
    根据选择模式状态切换导航栏内容:非选择模式显示常规标题和功能按钮,选择模式显示已选数量、批量操作按钮和退出选择的返回按钮,可搭配AnimatedSwitcher实现平滑切换动效
  • 可选优化:给选中状态切换、列表项图标替换增加过渡动画,和Gmail的动效体验对齐

核心代码示例

// 列表项构建逻辑示例
Widget buildListItem(ItemModel item) {
  final isSelected = selectedIds.contains(item.id);
  return InkWell(
    onTap: () {
      if (inSelectMode) {
        setState(() {
          isSelected ? selectedIds.remove(item.id) : selectedIds.add(item.id);
        });
        return;
      }
      // 非选择模式下的正常点击逻辑,比如跳转详情页
      Navigator.push(context, MaterialPageRoute(builder: (_) => DetailPage(item: item)));
    },
    onLongPress: () {
      setState(() {
        selectedIds.add(item.id);
      });
    },
    child: AnimatedContainer(
      duration: const Duration(milliseconds: 200),
      color: isSelected ? Colors.lightBlue.shade100 : Colors.white,
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      child: Row(
        children: [
          inSelectMode
              ? Icon(
                  isSelected ? Icons.check_circle : Icons.radio_button_unchecked,
                  color: Colors.blue,
                )
              : CircleAvatar(child: Text(item.avatarLabel)),
          const SizedBox(width: 16),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(item.title, style: const TextStyle(fontWeight: FontWeight.w500)),
                const SizedBox(height: 4),
                Text(item.subTitle, style: TextStyle(color: Colors.grey.shade600)),
              ],
            ),
          )
        ],
      ),
    ),
  );
}

内容的提问来源于stack exchange,提问作者Userrrrrr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 13:21:03