SwiftUI MapKit Map - Selecting Points of Interest

Is it possible to let the user select points of interest on the Map, such as restaurants, grocery stores, gas stations etc. I want the user to be able to select these points of interest that are already on the map, not those that I add to the map. Is this possible with the SwiftUI version of the MapKit Map?

Answered by DTS Engineer in 811635022

Yes, that's possible! Add the mapFeatureSelectionAccessory(_:) modifier to your Map.

—Ed Ford,  DTS Engineer

Accepted Answer

Yes, that's possible! Add the mapFeatureSelectionAccessory(_:) modifier to your Map.

—Ed Ford,  DTS Engineer

I had previously passed selectedItem to the selection parameter. Is it possible to allow selection of MKMapItems and MapFeatures?

Yes it is, new to iOS 18.

— Ed Ford,  DTS Engineer

Is there something additional that needs to be specified for the Map to allow the MapFeatures and Markers to be selected?

Here's something to try, through you'll need to make some small modifications to handle your search results.

struct MapView: View {
    
    @Environment(MapModel.self) private var mapModel
    
    /// The `MapCameraPosition` describes how to position the map’s camera within the map.
    @State private var mapCameraPosition: MapCameraPosition = .automatic
    
    /// The currently selected map feature.
    @State private var selection: MapSelection<MKMapItem>?
    
    var body: some View {
        @Bindable var mapModel = mapModel
        
        Map(position: $mapCameraPosition, selection: $selection) {
            UserAnnotation()
            
            ForEach(mapModel.searchResults, id: \.self) { result in
                /*
                 Display each search result as an annotation on the map using MapKit's default
                 annotation style, including iconography based on the map item's point-of-interest category.
                 The `tag` modifier enables selection of these items through the `selection` binding.
                 */
                Marker(item: result)
                    .tag(MapSelection(result))
            }
            
            /*
             This selection accessory modifier allows people to tap on the annotations that the app adds to the map and get more detailed
             information on the annotation, which displays as either a sheet or a callout according to the `style` parameter. Along with
             the `selection` binding, this determines which annotation to display additional information for.
             
             This modifier differs from the `mapFeatureSelectionAccessory(:_) modifier, which enables the same selection
             behaviors on map features, such as points of interest that `Map` displays.
             */
            .mapItemDetailSelectionAccessory(.automatic)
        }
        
        .mapStyle(.standard(pointsOfInterest: mapModel.searchConfiguration.pointOfInterestOptions.categories))
        
        // Only allow selection for points of interest, and disable selection of other labels, like city names.
        .mapFeatureSelectionDisabled { feature in
            feature.kind != MapFeature.FeatureKind.pointOfInterest
        }
        
        /*
         The selection accessory allows people to tap on map features and get more detailed information, which displays
         as either a sheet or a callout according to the `style` parameter. Along with the `selection` binding, this determines
         which feature to display additional information for.
         
         This modifier differs from the `mapItemDetailSelectionAccessory(:_) modifier, which enables the same selection
         behaviors on annotations that the app adds to `Map` for search results.
         */
        .mapFeatureSelectionAccessory(.automatic)
        
        .onMapCameraChange(frequency: .onEnd) { cameraContext in
            // When the camera changes position, such as when a person moves or zooms the map, update
            // the region the app uses for searching to reflect the changes to the visible map region.
            mapModel.searchConfiguration.region = cameraContext.region
        }
        .onChange(of: mapModel.searchResults) {
            // Adjust the map camera to make all of the annotations representing the search results visible.
            mapCameraPosition = .automatic
        }
        .onChange(of: selection) { _, newSelection in
            updateModelWithSelectedFeature(newSelection)
        }
    }
    
    private func updateModelWithSelectedFeature(_ selection: MapSelection<MKMapItem>?) {
        if let mapItem = selection?.value {
            // The person has selected an annotation, such as a search result.
            
        } else if let feature = selection?.feature {
            // The person has selected a map feature, such as a point of interest. Because the map feature doesn't contain the
            // details as an `MKMapItem`, request a map item for the feature.
            Task {
                let request = MKMapItemRequest(feature: feature)
                var mapItem: MKMapItem? = nil
                do {
                    mapItem = try await request.mapItem
                    mapModel.selectedMapItem = mapItem
                } catch let error {
                    let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: "Map Item Requests")
                    logger.error("Getting map item from map feature failed. Error: \(error.localizedDescription)")
                }
            }
        } else {
            
        }
    }
}

— Ed Ford,  DTS Engineer

SwiftUI MapKit Map - Selecting Points of Interest
 
 
Q