Detect long presses by multiple fingers with SwiftUI

101 Views Asked by At

Is there a good code example (or documentation) that shows how to detect long presses done by multiple fingers at the (almost) same time.

I would like to draw a circle around each finger.

With long press and drag gesture chained gives me the location of one long press. I want to know how to do it for multiple long presses.

This is the code I have now for detecting long presses and getting their location on the screen.

struct ContentView: View {
    @State private var showCircle = false
    @State private var tapLocation = CGPoint.zero

    var longPressed: some Gesture {
        LongPressGesture(minimumDuration: 1)
            .sequenced(
                before: DragGesture(
                    minimumDistance: 0,
                    coordinateSpace: .local
                )
            )
            .onEnded { value in
                switch value {
                case .second(true, let drag):
                    tapLocation = drag?.location ?? .zero
                    showCircle = true
                default:
                    break
                }
            }
    }

    var body: some View {
        ZStack {
            Rectangle()
                .foregroundColor(Color(.background))
                .ignoresSafeArea()
                .gesture(longPressed)
                .overlay(
                    Circle()
                        .foregroundColor(Color.random())
                        .frame(width: 100, height: 100)
                        .position(tapLocation)
                        .opacity(showCircle ? 1 : 0 )
                        .allowsHitTesting(false)
                )

            VStack(spacing: 8) {
                Image(systemName: "hand.tap")
                    .imageScale(.large)
                    .foregroundStyle(.tint)
                    .font(.largeTitle)
                Text("Tap and hold to start")
            }
            .padding()
        }
    }
}
2

There are 2 best solutions below

3
SaTisH ShiYaNi On
    struct ContentView: View {
        // State variable to keep track of long press state
        @State private var isLongPressing = false
        
        var body: some View {
            VStack {
                // View to detect long press
                Rectangle()
                    .fill(isLongPressing ? Color.red : Color.blue)
                    .frame(width: 200, height: 200)
                    .gesture(
                        LongPressGesture(minimumDuration: 1.0) // Adjust duration as needed
                            .onChanged { _ in
                                // Long press detected, update state
                                isLongPressing = true
                            }
                            .onEnded { _ in
                                // Long press ended, update state
                                isLongPressing = false
                            }
                    )
                    .padding()
                
                // Display long press state
                Text(isLongPressing ? "Long Pressing" : "Not Long Pressing")
                    .padding()
            }
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
} }
2
Anshul On

SwiftUI not provide a direct way to detect a long press gesture with a specific number of fingers out of the box. You can achieve this by using UIKit's UILongPressGestureRecognizer and integrating it into your SwiftUI.

import SwiftUI
import UIKit

struct MultiFingerLongPressGesture: UIViewRepresentable {
    var minimumFingerCount: Int
    var onLongPress: () -> Void

    func makeUIView(context: Context) -> UIView {
        let view = UIView(frame: .zero)
        view.backgroundColor = .clear // Make the background clear to not interfere visually.

        let longPressRecognizer = UILongPressGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.longPressed))
        longPressRecognizer.minimumPressDuration = 0.5 
        longPressRecognizer.numberOfTouchesRequired = minimumFingerCount

        view.addGestureRecognizer(longPressRecognizer)

        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {
         
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(onLongPress: onLongPress)
    }

    class Coordinator: NSObject {
        var onLongPress: () -> Void

        init(onLongPress: @escaping () -> Void) {
            self.onLongPress = onLongPress
        }

        @objc func longPressed() {
            onLongPress()
        }
    }
}

struct ContentView: View {
    var body: some View {
        MultiFingerLongPressGesture(minimumFingerCount: 2) {
            print("Long press detected with two fingers")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.blue.opacity(0.3))
    }
}