在SwiftUI中处理双手势识别器和三手势识别器

6

我正在尝试在SwiftUI中区分双击和三连击手势识别器。在基于Storyboard的应用程序中,可以使用UIGestureRecognizerDelegate实现,但是在SwiftUI中我没有找到任何解决方案。

注意:

以下方法不起作用:

.onTapGesture(count: 3) {
    print("Triple Tap!")
}
.onTapGesture(count: 2) {
    print("Double Tap!")
}
4个回答

5

如果我可以这样说,这是正确的方法!

在iOS 14.4.2和Xcode 12.5 beta 3上进行测试。

使用此tapGesture,在单击后什么也不会发生,在双击后,您将在控制台中看到“double tap”字样,而在三次或更多次点击后,您将在控制台中看到“triple tap”字样。

struct ContentView: View {
    var tapGesture: some Gesture {
        SimultaneousGesture(TapGesture(count: 2), TapGesture(count: 3))
            .onEnded { gestureValue in
                if gestureValue.second != nil {
                    print("triple tap!")
                } else if gestureValue.first != nil {
                    print("double tap!")
                }
            }
    }
    
    var body: some View {
        Text("Hello World!")
            .gesture(tapGesture)
    }
}

4
为了能够满足不同项目的多种手势需求,苹果公司没有提供比普通手势更好的选择,将它们混合使用以达到所需手势有时会变得棘手。这里提供一种解决方案,可以无故障地工作!
一个名为“tapCountRecognizer”的自定义零故障手势,我们可以将其应用于任何视图中。由于同时工作,它可以实现单击、双击和三连击手势。
请注意,您也可以像这样使用它,仅限于双击和三连击手势:
.tapCountRecognizer(tapSensitivity: 250, doubleTapAction: doubleTapAction, tripleTapAction: tripleTapAction)

或者:

.tapCountRecognizer(doubleTapAction: doubleTapAction, tripleTapAction: tripleTapAction)

enter image description here


import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        Circle()
            .fill(Color.red)
            .frame(width: 100, height: 100, alignment: .center)
            .tapCountRecognizer(tapSensitivity: 250, singleTapAction: singleTapAction, doubleTapAction: doubleTapAction, tripleTapAction: tripleTapAction)
            .shadow(radius: 10)
            .statusBar(hidden: true)
        
    }
    
    func singleTapAction() { print("singleTapAction") }
    
    func doubleTapAction() { print("doubleTapAction") }
    
    func tripleTapAction() { print("tripleTapAction") }
    
}

struct TapCountRecognizerModifier: ViewModifier {
    
    let tapSensitivity: Int
    let singleTapAction: (() -> Void)?
    let doubleTapAction: (() -> Void)?
    let tripleTapAction: (() -> Void)?
    
    
    init(tapSensitivity: Int = 250, singleTapAction: (() -> Void)? = nil, doubleTapAction: (() -> Void)? = nil, tripleTapAction: (() -> Void)? = nil) {
        
        self.tapSensitivity  = ((tapSensitivity >= 0) ? tapSensitivity : 250)
        self.singleTapAction = singleTapAction
        self.doubleTapAction = doubleTapAction
        self.tripleTapAction = tripleTapAction
        
    }
    
    @State private var tapCount: Int = Int()
    @State private var currentDispatchTimeID: DispatchTime = DispatchTime.now()
    
    func body(content: Content) -> some View {

        return content
            .gesture(fundamentalGesture)
        
    }
    
    var fundamentalGesture: some Gesture {
        
        DragGesture(minimumDistance: 0.0, coordinateSpace: .local)
            .onEnded() { _ in tapCount += 1; tapAnalyzerFunction() }
        
    }
    
    
    
    func tapAnalyzerFunction() {
        
        currentDispatchTimeID = dispatchTimeIdGenerator(deadline: tapSensitivity)
        
        if tapCount == 1 {
            
            let singleTapGestureDispatchTimeID: DispatchTime = currentDispatchTimeID
            
            DispatchQueue.main.asyncAfter(deadline: singleTapGestureDispatchTimeID) {

                if (singleTapGestureDispatchTimeID == currentDispatchTimeID) {

                    if let unwrappedSingleTapAction: () -> Void = singleTapAction { unwrappedSingleTapAction() }

                    tapCount = 0
                    
                }
                
            }
            
        }
        else if tapCount == 2 {
            
            let doubleTapGestureDispatchTimeID: DispatchTime = currentDispatchTimeID
            
            DispatchQueue.main.asyncAfter(deadline: doubleTapGestureDispatchTimeID) {
                
                if (doubleTapGestureDispatchTimeID == currentDispatchTimeID) {
 
                    if let unwrappedDoubleTapAction: () -> Void = doubleTapAction { unwrappedDoubleTapAction() }
                    
                    tapCount = 0
                    
                }
                
            }
            
        }
        else  {
            
            
            if let unwrappedTripleTapAction: () -> Void = tripleTapAction { unwrappedTripleTapAction() }
            
            tapCount = 0
            
        }
        
    }
    
    func dispatchTimeIdGenerator(deadline: Int) -> DispatchTime { return DispatchTime.now() + DispatchTimeInterval.milliseconds(deadline) }
    
}

extension View {
    
    func tapCountRecognizer(tapSensitivity: Int = 250, singleTapAction: (() -> Void)? = nil, doubleTapAction: (() -> Void)? = nil, tripleTapAction: (() -> Void)? = nil) -> some View {
        
        return self.modifier(TapCountRecognizerModifier(tapSensitivity: tapSensitivity, singleTapAction: singleTapAction, doubleTapAction: doubleTapAction, tripleTapAction: tripleTapAction))
        
    }
    
}

这太疯狂了,这是唯一一个真正有效的方法,可以单独处理单击、双击等操作。你很厉害!干得好! - Roman Simenok

1
import SwiftUI

struct MultipleTaps: View {
    let doubleTap = TapGesture(count: 2).onEnded({print("Double Tap!")})
    let tripleTap = TapGesture(count: 3).onEnded({print("Triple Tap!")})
    var body: some View {
        let tripleBeforedouble = tripleTap.exclusively(before: doubleTap)

        return Text("Hello World!").gesture(tripleBeforedouble)
    }
}

struct MultipleTaps_Previews: PreviewProvider {
    static var previews: some View {
        MultipleTaps()
    }
}

这只能识别三次轻击。 - lsrggr
为了正确检测两次轻拍,似乎只需要用“同时使用(with: doubleTap)”替换“排他性(before: doubleTap)”即可。 - Sardorbek Ruzmatov

0

为此,您可以使用.gesture.simultaneously(with:)。从文档中了解到:将手势与另一个手势结合起来,创建一个新的手势,同时识别两个手势。 示例代码如下:

struct TwoGesturesView: View {
    var body: some View {
        Text("Hello World!")
            .gesture(TapGesture(count: 2).onEnded({
                print("Double Tap")
            })
            .simultaneously(with: TapGesture(count: 3).onEnded({
                print("Triple Tap")
            })))
        
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接