为了在项目中拥有一些适合每个人需要的多手势,Apple 提供的只是普通手势,将它们混合在一起以达到想要的手势有时会变得很棘手,这是一种拯救,没有 问题或错误!
这里有一个名为 interactionReader 的自定义 zero issue 手势,我们可以将其应用于任何 View。 LongPressGesture 和 TapGesture 同时。
import SwiftUI
struct ContentView: View {
var body: some View {
Circle()
.fill(Color.yellow)
.frame(width: 150, height: 150)
.interactionReader(longPressSensitivity: 250, tapAction: tapAction, longPressAction: longPressAction, scaleEffect: true)
.animation(Animation.easeInOut(duration: 0.2))
}
func tapAction() { print("tap action!") }
func longPressAction() { print("longPress action!") }
}
struct InteractionReaderViewModifier: ViewModifier {
var longPressSensitivity: Int
var tapAction: () -> Void
var longPressAction: () -> Void
var scaleEffect: Bool = true
@State private var isPressing: Bool = Bool()
@State private var currentDismissId: DispatchTime = DispatchTime.now()
@State private var lastInteractionKind: String = String()
func body(content: Content) -> some View {
let processedContent = content
.gesture(gesture)
.onChange(of: isPressing) { newValue in
currentDismissId = DispatchTime.now() + .milliseconds(longPressSensitivity)
let dismissId: DispatchTime = currentDismissId
if isPressing {
DispatchQueue.main.asyncAfter(deadline: dismissId) {
if isPressing { if (dismissId == currentDismissId) { lastInteractionKind = "longPress"; longPressAction() } }
}
}
else {
if (lastInteractionKind != "longPress") { lastInteractionKind = "tap"; tapAction() }
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(50)) {lastInteractionKind = "none"}
}
}
return Group {
if scaleEffect { processedContent.scaleEffect(lastInteractionKind == "longPress" ? 1.5: (lastInteractionKind == "tap" ? 0.8 : 1.0 )) }
else { processedContent }
}
}
var gesture: some Gesture {
DragGesture(minimumDistance: 0.0, coordinateSpace: .local)
.onChanged() { _ in if !isPressing { isPressing = true } }
.onEnded() { _ in isPressing = false }
}
}
extension View {
func interactionReader(longPressSensitivity: Int, tapAction: @escaping () -> Void, longPressAction: @escaping () -> Void, scaleEffect: Bool = true) -> some View {
return self.modifier(InteractionReaderViewModifier(longPressSensitivity: longPressSensitivity, tapAction: tapAction, longPressAction: longPressAction, scaleEffect: scaleEffect))
}
}