Library / Drag, swipe & scroll

Swipe action arming (swipe to archive)

Swiping a row until the action arms ("release to archive") — a tick when it arms and when it disarms.

0ms 100ms 200ms 300ms 400ms
Feel
A selection tick on crossing the commit point in either direction, so the finger knows the state flipped.
APIs
UISelectionFeedbackGeneratorDragGesture
Minimum OS
iOS 10+
Raw .md
SwiftUI
import SwiftUI

struct SwipeableRow: View {
    let title: String
    let onArchive: () -> Void

    @State private var offsetX: CGFloat = 0
    @State private var armed = false
    private let commitPoint: CGFloat = -96
    private let tick = UISelectionFeedbackGenerator()

    var body: some View {
        ZStack(alignment: .trailing) {
            Color.orange
            Label("Archive", systemImage: "archivebox")
                .foregroundStyle(.white).padding(.trailing, 24)

            Text(title)
                .frame(maxWidth: .infinity, alignment: .leading)
                .padding().background(.background)
                .offset(x: offsetX)
                .gesture(
                    DragGesture()
                        .onChanged { value in
                            offsetX = min(0, value.translation.width)
                            let nowArmed = offsetX < commitPoint
                            if nowArmed != armed {
                                armed = nowArmed
                                tick.selectionChanged() // arm & disarm
                            }
                        }
                        .onEnded { _ in
                            if armed { onArchive() }
                            withAnimation(.spring) { offsetX = 0; armed = false }
                        }
                )
        }
        .clipShape(RoundedRectangle(cornerRadius: 12))
        .frame(height: 56)
    }
}
Copied