iOS16中SwiftUI onMove重排控件不显示及长按禁用需求
解决iOS16 List编辑模式下重排控件不显示问题
问题说明
需求是仅在编辑模式激活时启用列表行的移动功能,同时禁止iOS16中通过长按列表行触发移动操作。当前遇到的问题是:点击编辑按钮激活编辑模式后,列表行的重排控件(拖动图标)不会自动显示,必须将该行滚出屏幕再滚回来才会出现。
问题原因
原代码中使用了独立的enableMove变量控制onMove的可用性,但该变量与EditMode状态的更新未绑定,导致SwiftUI无法感知到需要刷新列表的ForEach部分,进而没有触发重排控件的渲染。
解决方案
直接通过EditMode的状态控制onMove的启用,无需额外变量。这样编辑模式切换时,SwiftUI会自动刷新列表,立即显示重排控件,同时也能实现非编辑模式下禁用长按移动的需求。
修改要点
- 删除独立的
enableMove状态变量,直接用editModeCurrent == .active判断是否启用移动功能 - 调整
onMove的perform参数,绑定到EditMode的状态 - 简化编辑按钮逻辑,只负责切换
EditMode的状态
完整修改后的代码
struct ContentView: View { @State private var editModeCurrent: EditMode = .inactive var body: some View { NavigationSplitView { } detail: { List { ForEach(0..<200) { i in Button { } label: { CustomRow(i: i) } } // 直接通过EditMode状态控制onMove是否启用 .onMove(perform: editModeCurrent == .active ? move : nil) .onDelete(perform: removeRows) } .listStyle(.plain) .environment(\.editMode, $editModeCurrent) .toolbar { editButton } } .navigationTitle("Oceans") } private var editButton: some View { Button { editModeCurrent = editModeCurrent == .inactive ? .active : .inactive } label: { Text(editModeCurrent == .inactive ? "Edit" : "Done") .foregroundColor(.red) } } func move(from source: IndexSet, to destination: Int) { } func removeRows(at offsets: IndexSet) { } } struct CustomRow: View { let i: Int var body: some View { HStack { Text("\(i)") Spacer() Image(systemName: "minus.circle") } } }
额外说明
修改后不仅解决了重排控件不自动显示的问题,还天然实现了“仅编辑模式下允许移动”的需求:非编辑模式时onMove的perform为nil,iOS16的长按手势不会触发移动操作;激活编辑模式后,列表会立即刷新并显示重排控件,无需滚动屏幕。
内容的提问来源于stack exchange,提问作者User95797654974
相关产品推荐
相关产品推荐

