iosswiftswiftuimapkitswiftui-ontapgesture

How to have onTap gestures on Map and MapAnnotation both, without the two interferring with each other?


I have a SwiftUI Map with MapAnnotations. I would like to have an onTap gesture on the Map, so it deselects the selected annotations, and dissmisses a bottom sheet, etc. Also would like to have an onTap gesture on the annotation item (or just having a button as annotation view with an action there), which selects the annotation and do stuff. The problem: whenever I tap the annotation, the map's ontap gesture is triggered too. (When I tap on the map, it only triggers the map's action, so no problems there.) Here's some sample code:

import SwiftUI
import MapKit
import CoreLocation

struct ContentView: View {

   @State var region: MKCoordinateRegion =
   MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 47.333,
                                                     longitude: 19.222),
                      span: MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002))


   var body: some View {

       Map(coordinateRegion: $region,
annotationItems: AnnotationItem.sample) { annotation  in
           MapAnnotation(coordinate: annotation.location.coordinate) {
               VStack {
                   Circle()
                       .foregroundColor(.red)
                       .frame(width: 50)
                   Text(annotation.name)
               }
               .onTapGesture {
                   print(">> tapped child")
               }
           }
       }
       .onTapGesture {
           print(">> tapped parent")
       }
   }
}

I tap on the annotation, then:

>> tapped parent
>> tapped child

I tap on the map, then:

>> tapped parent

EDIT:

I have tried and didn't work:


Solution

  • Another little hack inspired by @Gergely Kovacs's above answer!

    var body: some View {
    
        Map(coordinateRegion: $region, interactionModes: [.zoom, .pan], annotationItems: AnnotationItem.sample) { annotation  in
            MapAnnotation(coordinate: annotation.location.coordinate) {
                VStack {
                    Circle()
                        .foregroundColor(.red)
                        .frame(width: 50)
                    Text(annotation.name)
                }
                .onLongPressGesture(minimumDuration: .zero, maximumDistance: .zero) {
                   print(">> Tapped child")
                }
            }
        }
        .onTapGesture {
            print(">> tapped parent")
        }
    }