SwiftUI如何仅在EditMode下启用列表Delete滑动删除手势
问题背景
需求为屏蔽NavigationView中列表项默认的左滑呼出Delete按钮的操作,仅当NavigationView进入编辑模式时,才开放列表项删除能力。
已尝试的无效方案:
- 基于
editMode环境变量判断,给onDelete修饰符条件传入删除闭包或nil,未生效 - 调用
deleteDisabled修饰符,传入绑定editMode状态的判断值,修饰符未响应editMode变化,始终保持初始状态的禁用逻辑
问题复现代码
@State private var list = [1,2,3,4,5] @State private var editMode = EditMode.inactive var body: some View { NavigationView { List { ForEach(list, id: \.self) { item in Text("\(item) \(String(self.editMode.isEditing))") } .onDelete(perform: self.editMode.isEditing ? { index in list.remove(atOffsets: index) } : nil) .deleteDisabled(!self.editMode.isEditing) // 始终保持删除禁用,编辑模式下也不生效 } .navigationBarItems(leading: EditButton(), trailing: Text(editMode == .active ? "Editing" : "Not Editing")) .environment(\.editMode, $editMode) } }
异常表现
editMode状态变化时,列表项内展示的编辑状态文本、导航栏尾部的状态提示文本均可正常更新,但同一作用域下的onDelete、deleteDisabled修饰符完全不响应editMode变化,不会同步更新逻辑。
测试环境:Xcode 14.0 Beta
修复方案
该异常是Xcode 14 Beta版本下SwiftUI列表修饰符的状态刷新缺陷导致:onDelete、deleteDisabled不会跟随editMode变化重新计算入参,只需给ForEach添加绑定编辑状态的id修饰符,强制编辑模式切换时重绘ForEach内容即可让修饰符的判断逻辑生效。
修复后可运行代码:
@State private var list = [1,2,3,4,5] @State private var editMode = EditMode.inactive var body: some View { NavigationView { List { ForEach(list, id: \.self) { item in Text("\(item) \(String(self.editMode.isEditing))") } .id(editMode.isEditing) // 编辑状态变化时强制重绘ForEach,触发修饰符逻辑更新 .onDelete(perform: editMode.isEditing ? { index in list.remove(atOffsets: index) } : nil) .deleteDisabled(!editMode.isEditing) } .navigationBarItems(leading: EditButton(), trailing: Text(editMode == .active ? "Editing" : "Not Editing")) .environment(\.editMode, $editMode) } }
实现说明
- 非编辑状态下
onDelete传入nil会直接屏蔽左滑呼出Delete按钮的系统交互,无需自定义手势拦截 - 进入编辑模式后,
onDelete正常传入删除闭包,列表行左侧会展示系统默认的删除减号控件,点击即可触发删除逻辑 - 如果正式版Xcode中仍存在状态不同步问题,可将自定义的
@State类型editMode替换为系统注入的@Environment(\.editMode) var editMode,避免自定义状态和系统EditButton的状态同步冲突。
内容的提问来源于stack exchange,提问作者jdelano
相关产品推荐
相关产品推荐

