I'm made some minor fixes, it works great.
function edited delete().
import SwiftUI
struct Delete: ViewModifier {
let action: () -> Void
@State var offset: CGSize = .zero
@State var initialOffset: CGSize = .zero
@State var contentWidth: CGFloat = 0.0
@State var willDeleteIfReleased = false
func body(content: Content) -> some View {
content
.background(
GeometryReader { geometry in
ZStack {
Rectangle()
.cornerRadius(radius: 7, corners: [.topRight, .bottomRight])
.foregroundColor(.red)
Image(systemName: "trash")
.foregroundColor(.white)
.font(.title2.bold())
.layoutPriority(-1)
}
.frame(width: -offset.width)
.clipShape(Rectangle() )
.offset(x: geometry.size.width)
.onAppear {
contentWidth = geometry.size.width
}
.gesture(
TapGesture()
.onEnded {
delete()
}
)
}
)
.offset(x: offset.width, y: 0)
.gesture (
DragGesture()
.onChanged { gesture in
if gesture.translation.width + initialOffset.width <= 0 {
self.offset.width = gesture.translation.width + initialOffset.width
}
if self.offset.width < -deletionDistance && !willDeleteIfReleased {
hapticFeedback()
willDeleteIfReleased.toggle()
} else if offset.width > -deletionDistance && willDeleteIfReleased {
hapticFeedback()
willDeleteIfReleased.toggle()
}
}
.onEnded { _ in
if offset.width < -deletionDistance {
delete()
} else if offset.width < -halfDeletionDistance {
offset.width = -tappableDeletionWidth
initialOffset.width = -tappableDeletionWidth
} else {
offset = .zero
initialOffset = .zero
}
}
)
.animation(.interactiveSpring())
}
private func delete() {
//offset.width = -contentWidth
offset = .zero
initialOffset = .zero
action()
}
private func hapticFeedback() {
let generator = UIImpactFeedbackGenerator(style: .medium)
generator.impactOccurred()
}
//MARK: Constants
let deletionDistance = CGFloat(200)
let halfDeletionDistance = CGFloat(50)
let tappableDeletionWidth = CGFloat(100)
}
extension View {
func onDelete(perform action: @escaping () -> Void) -> some View {
self.modifier(Delete(action: action))
}
func cornerRadius(radius: CGFloat, corners: UIRectCorner) -> some View {
ModifiedContent(content: self, modifier: CornerRadiusStyle(radius: radius, corners: corners))
}
}
struct CornerRadiusShape: Shape {
var radius = CGFloat.infinity
var corners = UIRectCorner.allCorners
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
struct CornerRadiusStyle: ViewModifier {
var radius: CGFloat
var corners: UIRectCorner
func body(content: Content) -> some View {
content
.clipShape(CornerRadiusShape(radius: radius, corners: corners))
}
}