I'm developing an app, one view of which has the primary goal of allowing users to reorder a List of NavigationLinks, but which I would also like to allow navigation & a few other things. I want users to be able to:
- Reorder by dragging on the reorder control.
- Navigate to the link by tapping elsewhere on the row.
- Swipe from the leading edge to activate a swipe action.
At the moment, enabling EditMode (to allow reordering) disables navigation & swipe actions; I haven't been able to find a workaround that allows all 3 functions simultaneously. Is there a good way to do this?
Here's an example:
struct ReorderableListView: View {
var items: [X] // List of custom objects
var body: some View {
NavigationView {
List {
ForEach(items) { item in
NavigationLink(destination: CustomView(item)) { // winds up disabled by edit mode
Text(item.name)
}
.swipeActions(edge: .leading) { Button("Swipe") {print("swipe")} } // winds up disabled by edit mode
}
.onMove { from, to in
print("move \(from) to \(to)")
}
}
.environment(\.editMode, .constant(.active)) // always in edit mode for reordering
}
}
}
Update:
Based on the accepted answer, it looks like this behavior got updated in iOS 16: Now, if onMove
is implemented, you can reorder with a long press even when not in edit mode, which allows these three actions to coexist. I've added custom drag-handles to make this behavior obvious to the user, but otherwise I'm going with exactly the solution given in the accepted answer, below.