I am trying to prevent the 'swipe-back' animation after an alert is presented. Below is the reproducible code:
struct ContentView: View {
@State private var showingAlert = false
var body: some View {
List {
Text("Archive")
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button {
showingAlert = true
} label: {
Image(systemName: "archivebox.fill")
}
.tint(.yellow)
}
.alert("Archive?", isPresented: $showingAlert) {
Button("Archive") {
showingAlert = true
}
Button("Cancel", role: .cancel) {
showingAlert = false
}
} message: {
Text("Some message")
}
}
}
}
Here is how it looks:
But I want the row to stay in place so that the archive button is visible, and to animate back upon user interaction (if they choose cancel or archive). I guess this is possible?
One way to show the alert while the swipe action is showing is to cover the action button with an overlay and use this for triggering the alert.
GeometryReader
can be used to detect, when the row has been offset to the left. This is quite a reliable way of detecting, when the swipe actions are showing..matchedGeometryEffect
.struct ContentView: View {
@State private var showingAlert = false
@State private var rowWithSwipeActions: UUID?
@State private var rowId = UUID()
@Namespace private var ns
var body: some View {
ZStack {
List {
Text("Archive")
.id(rowId)
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button {} label: {
Image(systemName: "archivebox.fill")
}
.tint(.yellow)
}
.listRowBackground(
GeometryReader { proxy in
let minX = proxy.frame(in: .global).minX
HStack(spacing: 0) {
Color(.secondarySystemGroupedBackground)
.frame(width: proxy.size.width)
if minX < 0 {
Color.clear
.frame(minWidth: 74)
.matchedGeometryEffect(id: rowId, in: ns, isSource: true)
.onAppear { rowWithSwipeActions = rowId }
.onDisappear { rowWithSwipeActions = nil }
}
}
}
)
}
.alert("Archive?", isPresented: $showingAlert) {
Button("Archive") {
withAnimation { rowId = UUID() }
}
Button("Cancel", role: .cancel) {
withAnimation { rowId = UUID() }
}
} message: {
Text("Some message")
}
if let rowWithSwipeActions {
Color.black
.opacity(0.001)
.onTapGesture {
showingAlert = true
}
.matchedGeometryEffect(id: rowWithSwipeActions, in: ns, isSource: false)
}
}
}
}