1

I am trying to get SwiftUI + MapKit + LongPress gesture working. When I add the map within the ContentView, it works great. I then add the .onLongPressGesture modifier to the map, and the panning/zooming stops working. Long press works though.

The code I am working on:

Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true)
  .onLongPressGesture {
    // How do I get the location (Lat/Long) I am pressed on?
    print("onLongPressGesture")
  }

Also, is there a way to get the lat/long from the long press gesture?

Looking to make it work using SwiftUI only, without wrapping UIKit within a UIViewRepresentable.

Roland Lariotte
  • 2,606
  • 1
  • 16
  • 40

2 Answers2

2

Don't ask why but this seems to work:

    Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true)
        .gesture(DragGesture())
        .onLongPressGesture {
            print("Here!")
        }
ChrisR
  • 9,523
  • 1
  • 8
  • 26
  • Based on ChrisR gesture I looked into using gesture I think this is the right way to do it `Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true) .gesture(DragGesture()) .gesture( LongPressGesture() .onEnded { value in print("LongPressGesture "+value.description) } )` Still can not figure out how to get lat/long, Any Ideas? I know you take the x,y of the screen and convert to lat/long – tom hackbarth Mar 09 '22 at 14:33
  • getting the tap/longpress location unfortunately is not that easy in SwiftUI ... start from here: https://stackoverflow.com/questions/56513942/how-to-detect-a-tap-gesture-location-in-swiftui – ChrisR Mar 09 '22 at 16:14
  • Once you have the press location you can relate that you your currently shown coordinateRegion and recalculate into lat/lon. – ChrisR Mar 09 '22 at 16:15
  • btw: a much simpler approach would be to have some fixed circle or crosshairs in the center of the screen which sets a new pinned location on button press. btw2: SwiftUI's Map View is very very basic compared to UIKit. – ChrisR Mar 09 '22 at 16:17
0

Yep.

I wrapped MKMapView in UIViewRepresentable and added long press gesture recognizer in the delegate method like this:

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
            // We need to update the region when the user changes it
            // otherwise when we zoom the mapview will return to its original region
            DispatchQueue.main.async {
                if self.longPress == nil {
                    let recognizer = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressGesture(recognizer:)))
                    mapView.addGestureRecognizer(recognizer)
                    self.longPress = recognizer
                }
                self.parent.region = mapView.region
            }
        }

Then

    @objc func longPressGesture(recognizer: UILongPressGestureRecognizer) {
        if let mapView = recognizer.view as? MKMapView {
            let touchPoint = recognizer.location(in: mapView)
            let touchMapCoordinate =  mapView.convert(touchPoint, toCoordinateFrom: mapView)
            
            // TODO: check if we already have this location and bail out
            if annotations.count > 0 {
                return
            }
            
            let annotation = Annotation(title: touchMapCoordinate.stringValue, coordinate: touchMapCoordinate)
            mapView.removeAnnotations(annotations.compactMap({ $0.pointAnnotation }))
            annotations.append(annotation)
            mapView.addAnnotation(annotation.pointAnnotation)
        }
    }

Using the code from this answer: https://stackoverflow.com/a/71698741/1320010

Cherpak Evgeny
  • 2,659
  • 22
  • 29