Implementing a Custom Swipe‑to‑Delete Interaction in SwiftUI Using Gesture Modifiers
This article demonstrates how to build a custom left‑swipe delete interaction for SwiftUI list cards by using DragGesture, state handling, visual cues, confirmation alerts, hint text, and haptic feedback, offering a more flexible alternative to the built‑in List deletion.
In the previous chapter we introduced the MVVM pattern and a simple delete action triggered by SwiftUI's contextMenu on a long‑press; this method deletes an item by calling a ViewModel function with the item's UUID.
For card‑style lists a more common UX is a left‑to‑right swipe that reveals a delete action. The built‑in EditButton swipe often has limitations, so we implement a custom gesture‑based solution.
SwiftUI provides three main gestures: onTapGesture, LongPressGesture, and DragGesture. We start by attaching a DragGesture to the card view:
// Drag gesture
.gesture(
DragGesture()
.onChanged { value in
// actions while dragging
}
.onEnded { value in
// actions when drag ends
}
)We declare a @GestureState (or a regular @State) called viewState to store the current translation:
@State var viewState = CGSize.zeroThe card view receives an .offset modifier that only allows movement to the left:
// Allow dragging only from right to left
.offset(x: self.viewState.width < 0 ? self.viewState.width : 0)During the drag we update viewState with the translation and reset it to .zero when the gesture ends:
.gesture(
DragGesture()
.onChanged { value in
self.viewState = value.translation
}
.onEnded { value in
self.viewState = .zero
}
)To decide when a swipe should trigger deletion we define a threshold and a Boolean flag:
@State var valueToBeDeleted: CGFloat = -75
@State var readyToBeDeleted: Bool = falseInside the gesture we compare the current offset with the threshold:
self.readyToBeDeleted = self.viewState.width < self.valueToBeDeleted ? true : falseIf the flag is true we change the card background to red, otherwise keep it white:
.background(self.readyToBeDeleted ? Color(.systemRed) : .white)When the drag finishes we reset readyToBeDeleted to false so the UI returns to its normal state.
The actual removal is performed in the ViewModel. We add a method to fetch an item by its UUID and another to delete it:
// Get item by UUID
func getItemById(itemId: UUID) -> Model? {
return models.first { $0.id == itemId } ?? nil
}
// Delete item
func deleteItem(itemId: UUID) { /* implementation */ }Each CardView receives the ViewModel, the item’s UUID, and a computed item property that calls getItemById:
var viewModel: ViewModel
var itemId: UUID
var item: Model? { viewModel.getItemById(itemId: itemId) }When the swipe passes the threshold we present a confirmation alert before calling deleteItem:
@State var showDeleteAlert: Bool = false
private var deleteAlert: Alert {
Alert(
title: Text(""),
message: Text("确定要删除吗?"),
primaryButton: .destructive(Text("确认")) { /* delete */ },
secondaryButton: .cancel(Text("取消"))
)
}
// Attach alert to the card view
.alert(isPresented: $showDeleteAlert) { deleteAlert }We also add a hint text that becomes visible behind the card when it is swiped left:
HStack {
Spacer()
Text("左滑删除")
.padding()
.foregroundColor(Color(.systemGray))
}To give tactile feedback we create a small utility struct:
import Foundation
import SwiftUI
struct Haptics {
static func hapticSuccess() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.success)
}
static func hapticWarning() {
let generator = UINotificationFeedbackGenerator()
generator.notificationOccurred(.warning)
}
}During the swipe we call Haptics.hapticWarning() to signal a potentially destructive action.
By combining gesture handling, state management, visual cues, confirmation alerts, hint text, and haptic feedback we achieve a polished, custom swipe‑to‑delete experience that goes beyond the default List behavior, illustrating how SwiftUI can be extended when built‑in components are insufficient.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
