鸿蒙Flutter实战:多选批量删除模式的实现

发布时间:2026/6/25 13:36:33

鸿蒙Flutter实战:多选批量删除模式的实现 前言单条删除用滑动操作就够了。但如果用户想一口气删除十几条过期的备忘录一条一条滑得累死。批量删除需要一套选择模式——用户通过长按进入选择态勾选多个条目然后一键删除。这和文件管理器、相册的多选逻辑是一样的长按激活选择模式 → 点击勾选/取消 → 全选/反选 → 批量操作。本文拆解鸿蒙 Flutter 备忘录中这个功能的完整实现。项目仓库todo_flutter_harmony状态设计选择模式需要在MemoProvider中维护两组状态classMemoProviderextendsChangeNotifier{bool _isSelectionModefalse;finalSetint_selectedIds{};boolgetisSelectionMode_isSelectionMode;SetintgetselectedIdsSet.unmodifiable(_selectedIds);intgetselectedCount_selectedIds.length;// 进入选择模式voidenterSelectionMode(int initialId){_isSelectionModetrue;_selectedIds.add(initialId);notifyListeners();}// 退出选择模式voidexitSelectionMode(){_isSelectionModefalse;_selectedIds.clear();notifyListeners();}// 切换某个条目的选中状态voidtoggleSelection(int id){if(_selectedIds.contains(id)){_selectedIds.remove(id);if(_selectedIds.isEmpty){_isSelectionModefalse;// 全部取消后自动退出选择模式}}else{_selectedIds.add(id);}notifyListeners();}// 全选voidselectAll(){_selectedIds.addAll(_allMemos.map((m)m.id!));notifyListeners();}// 取消全选voiddeselectAll(){_selectedIds.clear();_isSelectionModefalse;notifyListeners();}// 批量删除FuturevoiddeleteSelected()async{for(finalidin_selectedIds){awaitDatabaseHelper.instance.deleteMemo(id);}_selectedIds.clear();_isSelectionModefalse;awaitloadMemos();}}核心设计要点_selectedIds是一个SetintO(1) 的查找和删除效率所有选中项都被取消后自动退出选择模式deleteSelected是异步方法逐条删除后重新加载数据AppBar 的动态切换选择模式下AppBar 从备忘录列表变为批量操作栏classMemoListPageextendsStatelessWidget{overrideWidgetbuild(BuildContextcontext){returnScaffold(appBar:ConsumerMemoProvider(builder:(context,provider,_){if(provider.isSelectionMode){return_buildSelectionAppBar(provider);}return_buildNormalAppBar(context);},),body:_buildBody(),);}选择模式 AppBarAppBar_buildSelectionAppBar(MemoProviderprovider){returnAppBar(leading:IconButton(icon:constIcon(Icons.close),onPressed:()provider.exitSelectionMode(),),title:Text(已选择${provider.selectedCount}项),actions:[// 全选/取消全选TextButton(onPressed:(){if(provider.selectedCountprovider.memos.length){provider.deselectAll();}else{provider.selectAll();}},child:Text(provider.selectedCountprovider.memos.length?取消全选:全选,style:constTextStyle(color:Colors.white),),),// 删除按钮IconButton(icon:constIcon(Icons.delete_outline),onPressed:provider.selectedCount0?()_confirmBatchDelete(context,provider):null,),],backgroundColor:constColor(0xFFE53935),// 红色背景警告态);}红色背景的 AppBar 在视觉上给用户一个明确的信号——“你在操作模式中小心”。删除确认对话框批量删除是不可逆操作必须有确认环节void_confirmBatchDelete(BuildContextcontext,MemoProviderprovider){showDialog(context:context,builder:(ctx)AlertDialog(title:constText(确认删除),content:Text(确定要删除选中的${provider.selectedCount}条备忘录吗此操作不可撤销。),actions:[TextButton(onPressed:()Navigator.pop(ctx),child:constText(取消),),TextButton(onPressed:(){provider.deleteSelected();Navigator.pop(ctx);ScaffoldMessenger.of(context).showSnackBar(SnackBar(content:Text(已删除${provider.selectedCount}条备忘录)),);},style:TextButton.styleFrom(foregroundColor:Colors.red),child:constText(删除),),],),);}列表项的多选 UI选择模式下的列表项需要显示复选框Widget_buildMemoItem(Memomemo,MemoProviderprovider){finalisSelectedprovider.selectedIds.contains(memo.id);returnGestureDetector(onLongPress:(){if(!provider.isSelectionMode){provider.enterSelectionMode(memo.id!);HapticFeedback.mediumImpact();// 触觉反馈}},onTap:(){if(provider.isSelectionMode){provider.toggleSelection(memo.id!);}else{// 正常模式打开编辑页Navigator.pushNamed(context,/memo/edit,arguments:memo.id);}},child:AnimatedContainer(duration:constDuration(milliseconds:200),color:isSelected?constColor(0xFF4DB6AC).withOpacity(0.08):Colors.transparent,child:Row(children:[// 选择模式下显示复选框if(provider.isSelectionMode)Padding(padding:constEdgeInsets.only(left:16),child:Icon(isSelected?Icons.check_circle:Icons.radio_button_unchecked,color:isSelected?constColor(0xFF4DB6AC):Colors.grey.shade400,),),// 卡片内容Expanded(child:MemoCard(memo:memo)),],),),);}关键交互细节长按进入选择模式onLongPress触发enterSelectionMode同时播放HapticFeedback.mediumImpact()触觉反馈点击行为分流选择模式下点击 勾选/取消正常模式下点击 打开编辑页选中背景色AnimatedContainer的color从透明过渡到 8% 透明度主题色复选框 icon用check_circle/radio_button_unchecked替代 MaterialCheckboxwidget风格更轻量防止内存泄漏批量删除中的 mounted 检查批量删除是异步操作删除过程中用户可能导航到其他页面FuturevoiddeleteSelected()async{finalidsToDeleteSetint.from(_selectedIds);_selectedIds.clear();_isSelectionModefalse;notifyListeners();for(finalidinidsToDelete){awaitDatabaseHelper.instance.deleteMemo(id);}awaitloadMemos();// loadMemos 会触发 notifyListeners()}注意此处先把_selectedIds拷贝一份再清空UI 立即更新移除红色 AppBar然后在后台逐条删除。如果用户在删除过程中导航离开widget 已被 disposeloadMemos中如果有notifyListeners()调用listener 不会引发崩溃——Provider 已经处理了这种情况。鸿蒙兼容性批量删除的实现完全在 Dart 层Setint状态管理Dart 标准库HapticFeedbackFlutter services 层在鸿蒙上调用 OHOS 振动 API需确认flutter_ohos引擎是否实现了振动能力showDialog/AlertDialogMaterial 组件纯 Flutter 实现如果鸿蒙设备不支持 HapticFeedbackmediumImpact()会静默失败不会抛异常。这是一个很好的防御性编程实践。总结多选批量删除模式的关键在于状态转换长按→isSelectionMode trueAppBar 切换为红色操作栏点击→toggleSelection(id)Setint增删元素点击删除→ 确认对话框 → 逐条删除 → 重新加载取消/完成→exitSelectionMode()清空状态总共约 100 行 Provider 代码60 行 UI 代码实现了一套符合移动端直觉的批量操作交互。完整项目代码见todo_flutter_harmony

相关新闻