I've gotten around animation issues by using a ViewModifier to encapsulate not only the alert, but also the swipe action with the state variable. This cleans up the call site considerably.
Note that if you change the SwipeAction button role to destructive
as that role will delete the item from the list, removing the alert from the view. So I manually tinted the button red to get around this issue.
extension View {
func deleteSwipeActionAlert(title: LocalizedStringKey, message: LocalizedStringKey, action: @escaping () -> ()) -> some View {
modifier(DeleteSwipeActionAlertModifier(title: title, message: message, action: action))
}
}
struct DeleteSwipeActionAlertModifier : ViewModifier {
let title: LocalizedStringKey
let message: LocalizedStringKey
let action: () -> ()
@State private var isPresented: Bool = false
func body(content: Content) -> some View {
content
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button {
isPresented = true
} label: {
Label("Delete", systemImage: "trash")
}
.tint(.red)
}
.alert(title, isPresented: $isPresented) {
Button("Delete", role: .destructive, action: action)
Button("Cancel", role: .cancel) { }
} message: { Text(message) }
}
}
And an example of implementation:
struct TestList : View {
@State private var items = ["Item 1", "Item 2", "Item 3"]
var body: some View {
List($items, id: \.self) { item in
Text("List entry for [\(item.wrappedValue)]")
.deleteSwipeActionAlert(title: "Confirm delete", message: "Are you sure you want to delete?") {
items.remove(at: items.firstIndex(of: item.wrappedValue)!)
print("Do something to delete the record here.")
}
}
}
}
List(selection: $selection)
If i do this and add a custom delete button to show an alert before deletion the$selection
binding becomes empty. – Micromho