如何在Flutter中实现Gmail风格的TextFormField选择控制效果
Flutter 实现 Gmail 式列表选择控制教程
效果对比
- Flutter 默认选择控制效果:

- 目标 Gmail 选择控制效果:

核心实现逻辑
无需引入第三方依赖,按照以下步骤即可快速实现该效果:
- 状态管理:声明一个集合存储当前选中的列表项唯一标识,同时通过集合是否非空判断当前是否处于选择模式
// 存储选中的item id,类型可以根据你自己的item主键调整 Set<String> selectedIds = {}; // 快捷判断是否进入选择模式 bool get inSelectMode => selectedIds.isNotEmpty; - 列表项交互适配
分两种模式处理交互:- 非选择模式:点击列表项触发正常跳转/查看逻辑,长按列表项触发选择模式,同时把当前长按的项加入选中集合
- 选择模式:点击任意列表项切换该项目的选中状态,当所有选中项都被取消、集合为空时自动退出选择模式
列表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
相关产品推荐
相关产品推荐

