This is another issue found after changing to use a @StateObject for my data model when populating a List.
Previous issue is here: https://developer.apple.com/forums/thread/805202 - the entire List was being redrawn when one value changed, and it jumped to the top.
Here's some code:
struct ItemListView: View {
@State private var showAlert: Bool = false
...
fileprivate func drawItemRow(_ item: ItemDetails) -> some View {
return ItemRow(item: item)
.id(item.id)
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
RightSwipeButtons(showAlert: $showAlert, item: item)
}
}
...
List {
ForEach(modelData.filteredItems.filter { !$0.archived }) { item in
drawItemRow(item)
}
}
...
.alert("Delete Item"), isPresented: $showAlert) {
Button("Yes, delete", role: .destructive) {
deleteItem(item.id) // Not important how this item.id is gained
}
Button("Cancel", role: .cancel) { }
} message: {
Text("Are you sure you want to delete this item? You cannot undo this.")
}
}
struct RightSwipeButtons: View {
@Binding var showAlert: Bool
var body: some View {
Button { showAlert = true } label: { Label("", systemImage: "trash") }
}
}
The issue I have now is that when you swipe from the right to show the Delete button, and tap it, the alert is displayed but the list has jumped back to the top again. At this point you haven't pressed the delete button on the alert.
Using let _ = Self._printChanges() on both the ItemsListView and the individual ItemRows shows this:
ItemsListView: _showAlert changed.
ItemRow: @self, @identity, _accessibilityDifferentiateWithoutColor changed.
So yeah, that's correct, showAlert did change in ItemsListView, but why does the entire view get redrawn again, and fire me back to the top of the list?
You'll notice that it also says _accessibilityDifferentiateWithoutColor changed on the ItemRows, so I commented out their use to see if they were causing the issue, and... no.
Any ideas?
(Or can someone provide a working example of how to ditch SwiftUI's List and go back to a UITableView...?)