swiftuigesture-recognitionsingle-vs-double-tap

How to get double tap gesture touch location details in ios15


All, I would like to get double tap gesture tapped location coordinates to zoom tapped area. Using below code for single tap,

onTapGesture { location in print("Tapped at \(location)")

I need same location with double tap also in ios 15.

Thank you for support and answer will much helped.


Solution

  • This extension adds a custom double-tap gesture recognizer to a SwiftUI view, with options to customize the sensitivity and the location reporting of the double-tap.

    Parameters:

    sensitivity: A Double that defines the maximum time interval (in seconds) between two taps to be recognized as a double-tap. By default, it is set to 0.25 seconds.

    coordinateSpace: A CoordinateSpace value that determines the space in which the location of the double-tap will be reported. The default is .local, meaning the location is reported relative to the view’s local coordinate system.

    location: A closure that takes a CGPoint and is called when the double-tap occurs, providing the exact location of the tap.

    Functionality: The function applies a modifier (OnDoubleTapGestureViewModifier) to the view, which handles the double-tap gesture detection, applying the specified sensitivity and reporting the tap's location using the provided closure.

    Returns: A modified view with the double-tap gesture recognizer applied, which will respond to double-tap gestures and call the location closure with the coordinates of the tap.

    Requirements: Requires iOS 14.0 or later, or macOS 11.0 or later.


    import SwiftUI
    
    struct ContentView: View {
        
        @State private var doubleTapLocation: CGPoint? = nil
        
        var body: some View {
            Color.yellow
                .overlay(Text(describingDoubleTapLocation(value: doubleTapLocation)).bold())
                .onDoubleTapGesture { location in
                    doubleTapLocation = location
                    print("Double Tap! Location:" + String(describing: location))
                }
        }
        
        private func describingDoubleTapLocation(value: CGPoint?) -> String {
            if let unwrappedValue: CGPoint = value {
                return "Location: (" + formater(unwrappedValue.x) + ", " + formater(unwrappedValue.y) + ")"
            }
            else {
                return "Double tap me!"
            }
        }
        
        private func formater(_ value: CGFloat) -> String {
            return String(format: "%.2f", value)
        }
        
    }
    

    struct OnDoubleTapGestureViewModifier: ViewModifier {
        
        init(sensitivity: Double = 0.25, coordinateSpace: CoordinateSpace = .local, doubleTapLocation: @escaping (CGPoint) -> Void) {
            self.sensitivity = sensitivity
            self.coordinateSpace = coordinateSpace
            self.doubleTapLocation = doubleTapLocation
        }
        
        var sensitivity: Double
        var coordinateSpace: CoordinateSpace
        var doubleTapLocation: (CGPoint) -> Void
        
        @State private var resetTimer: Timer? = nil
        @State private var doubleTapCount: Int8 = 0
        
        func body(content: Content) -> some View {
            content
                .gesture(dragGesture)
        }
        
        private var dragGesture: some Gesture {
            DragGesture(minimumDistance: .zero, coordinateSpace: coordinateSpace)
                .onChanged { gestureValue in
                    
                    if (gestureValue.translation == .zero) {
                        
                        doubleTapCount += 1
                        
                        if (doubleTapCount == 2) {
                            resetTimer?.invalidate()
                            doubleTapCount = 0
                            doubleTapLocation(gestureValue.startLocation)
                        }
                        else {
                            resetTimer = Timer.scheduledTimer(withTimeInterval: sensitivity, repeats: false) {  _ in
                                doubleTapCount = 0
                            }
                        }
                        
                    }
                    
                }
                .onEnded { gestureValue in
                    
                    if (gestureValue.translation == .zero) {
                        if (doubleTapCount >= 2) {
                            resetTimer?.invalidate()
                            doubleTapCount = 0
                        }
                    }
                    
                }
        }
    }
    

    extension View {
        
        /// Adds a double-tap gesture recognizer to a view with customizable sensitivity and reports the location of the double-tap.
        ///
        /// - Requires: iOS 14.0 or later, macOS 11.0 or later.
        ///
        /// - Parameters:
        ///   - sensitivity: A `Double` value representing the maximum time interval (in seconds) between two taps to register as a double-tap. Default is `0.25`.
        ///   - coordinateSpace: The coordinate space in which the double-tap location should be reported. Default is `.local`.
        ///   - location: A closure that receives the `CGPoint` where the double-tap occurred.
        /// - Returns: A modified view with the double-tap gesture applied.
        func onDoubleTapGesture(sensitivity: Double = 0.25, coordinateSpace: CoordinateSpace = .local, location: @escaping (CGPoint) -> Void) -> some View {
            self.modifier(OnDoubleTapGestureViewModifier(sensitivity: sensitivity, coordinateSpace: coordinateSpace, doubleTapLocation: location))
        }
        
    }