16

I'm trying to add a MapAnnotation item to my Map() View from MapKit.

Everything works fine if you add coordinates manually in a TextField, but I can't find any way to add it by tapping on the map.

I've read a lot on the internet but I've found nothing about onTap() map event handling.

This is what my map view looks like so far:

struct MyMap : View {
    
    @State private var myRegion:MKCoordinateRegion = {
        var newRegion = MKCoordinateRegion()
        newRegion.center.latitude = 53.7576508
        newRegion.center.longitude = -11.1811597
        newRegion.span.latitudeDelta = 0.1
        newRegion.span.longitudeDelta = 0.1
        
        return newRegion
    }()
    
    
    @State private var annotationItems : [Annotation] = [
        Annotation(name: "Pin1", description: "myDescription", coordinate: CLLocationCoordinate2D(latitude: 123.7576508, longitude: -7.2373215))
    ]
    
    var body: some View {
        
        ZStack {
            Map(coordinateRegion: self.$myRegion, interactionModes: .all, annotationItems: annotationItems){ item in
                MapAnnotation(coordinate: item.coordinate){
                    PinView(pin: item)
                }
                
            }
            .edgesIgnoringSafeArea(.all)
        }
    }
}

Is there any way to get the coordinate of where user tapped on the map?

trndjc
  • 11,654
  • 3
  • 38
  • 51
Alessio Raddi
  • 540
  • 1
  • 6
  • 20
  • 1
    I deleted my answer because the OP wants the answer to be exclusively in SwiftUI. That said, https://stackoverflow.com/questions/56513942/how-to-detect-a-tap-gesture-location-in-swiftui may help. Furthermore, because UIKit and SwiftUI can work together side by side in the same project, you can take advantage of `convert(touch, toCoordinateFrom: mapView)` in the tap gesture handler in UIKit if it's too much trouble getting it in SwiftUI. – trndjc May 01 '21 at 16:40
  • Possibly same issue as https://stackoverflow.com/questions/63110673/tapping-an-mkmapview-in-swiftui – Vendel Serke Mar 10 '22 at 17:25
  • @trndjc Too bad you deleted your answer. Even if OP wanted it in pure SwiftUI, your answer still would have been very useful for someone else. – thedp Mar 06 '23 at 11:54
  • 1
    @thedp I undeleted it. – trndjc Mar 06 '23 at 17:34

2 Answers2

3

iOS 17 now has a MapReader for the SwiftUI map. You wrap the Map like this:

struct ContentView: View {
    var body: some View {
        MapReader { reader in
            Map()
            .onTapGesture(perform: { screenCoord in
                let pinLocation = reader.convert(screenCoord, from: .local)
                print(pinLocation)
            })
        }
    }
}

and you can extract the lat/long of the touch.

James Toomey
  • 5,635
  • 3
  • 37
  • 41
2

What you can do is add a tap gesture recognizer to the map and then convert the touch point to coordinates in the recognizer's handler:

@objc func tapMapAction(recognizer: UITapGestureRecognizer) {
    let touch = recognizer.location(in: mapView)
    let coord = mapView.convert(touch, toCoordinateFrom: mapView)

    let annot = MKPointAnnotation()
    annot.coordinate = coord
    mapView.addAnnotation(annot)
}

At the request of someone, I've undeleted this answer; also given that there is no accepted answer in SwiftUI and that UIKit is still the dominant framework for production-apps today.

trndjc
  • 11,654
  • 3
  • 38
  • 51
  • 2
    Yeah but SwiftUI not UIKit – aheze Apr 30 '21 at 15:37
  • 1
    The SwiftUI solution, as of now in its infancy, isn't very attractive (https://stackoverflow.com/questions/56513942/how-to-detect-a-tap-gesture-location-in-swiftui) so just use UIKit. There's nothing preventing anyone from mixing UIKit and SwiftUI in the same app. – trndjc Apr 30 '21 at 16:00
  • @bxod Is this answer compatible even for Map() or just MKMapView()? – Alessio Raddi May 01 '21 at 13:58
  • @AlessioRaddi if `Map()` is just an instance of `MKMapView()` then yes, which I assume it is. – trndjc May 01 '21 at 15:02
  • @bxod Nope, it’s a View introduced in SwiftUI 2.0 I guess. https://developer.apple.com/documentation/mapkit/map – Alessio Raddi May 01 '21 at 16:23
  • Now I understand, you are dealing exclusively in SwiftUI. `Map` is a SwiftUI component within MapKit which uses the same map as UIKit. 'Map` is simply a view with an embedded MapKit map. Your question should probably exclude the Swift tag and be slightly reworded to focus exclusively on SwiftUI. I don't know how this would work in SwiftUI exclusively because this is all very new in iOS but you can interoperate UIKit and SwiftUI which means that if you can't find an answer that is exclusively in SwiftUI then my answer would likely be the best alternative so I'll leave it up for that. – trndjc May 01 '21 at 16:33