swiftswiftuimapkit

How to select a marker in SwiftUI MapKit iOS 17?


I have a struct called CustomMarker that conforms to hashable:

struct CustomMarker: Identifiable, Hashable {
var id: String
var title: String
var location: CLLocationCoordinate2D
var category: String
var notes: String


func hash(into hasher: inout Hasher) {
    hasher.combine(id)
    hasher.combine(title)
    hasher.combine(location.latitude)
    hasher.combine(location.longitude)
    hasher.combine(category)
    hasher.combine(notes)
}

static func ==(lhs: CustomMarker, rhs: CustomMarker) -> Bool {
    return lhs.id == rhs.id &&
        lhs.title == rhs.title &&
        lhs.location.latitude == rhs.location.latitude &&
        lhs.location.longitude == rhs.location.longitude &&
        lhs.category == rhs.category &&
        lhs.notes == rhs.notes
}

}

Then I have an array of markers as such:

    @State private var markers: [CustomMarker] = [CustomMarker(id: "1", title: "First Marker", location: CLLocationCoordinate2D(latitude: 345, longitude: 235), category: "My Category", notes: "My Notes")]

Then I display my markers in my map:

Map(selection: self.$selectedMarker) {
                    
    UserAnnotation()
                    
    ForEach(self.markerManager.markers) { marker in
        Marker(marker.title, coordinate: marker.location)
            .tag(marker)
            .tint(self.categoryManager.categories.first(where: {$0.name == marker.category})?.pinColor ?? Color(hex: "FFFFFFC57C108"))
    }
                    
}
.mapControls {
MapCompass()
MapUserLocationButton()
MapScaleView()
}

From my understanding, the tag is supposed to select the marker and expand the marker pin as seen in this video: https://youtu.be/_-x24ng9moA?si=4tqAIWURBAwnfPjP&t=227

So far, the marker does not do anything when I click on it.

Any help is appreciated, thanks in advance :)


Solution

  • Since your CustomMarker id is a String, try this approach:

     @State private var selectedMarker: String? // <--- here
     
     var body: some View {
         VStack {
             Text(selectedMarker ?? "no selection") // <--- for testing
             Map(position: $cameraPosition, selection: $selectedMarker) {
                 ForEach(markerManager.markers) { marker in
                     Marker(marker.title, coordinate: marker.location)
                         .tag(marker.id) // <--- here
                 }
             }
         }
     }
    

    Or, using CustomMarker:

    @State private var selectedMarker: CustomMarker? // <--- here
    
    var body: some View {
        VStack {
            Text(selectedMarker?.title ?? "no selection") // <--- for testing
            Map(position: $cameraPosition, selection: $selectedMarker) {
                ForEach(markerManager.markers) { marker in
                    Marker(marker.title, coordinate: marker.location)
                        .tag(marker) // <--- here
                }
            }
        }
    }
    

    Note, there is no location at CLLocationCoordinate2D(latitude: 345, longitude: 235). Try Tokyo at: CLLocationCoordinate2D(latitude: 35.68, longitude: 139.75).

    Latitude: -90.0 to 90.0 degrees

    Longitude: -180.0 to 180.0 degrees