The iOS 17 MapKit API replaces the old wrapped Map view with a full SwiftUI integration.
Map takes a MapContentBuilder closure, a result builder like ViewBuilder but for types
conforming to MapContent. The old Map is deprecated but still useful on earlier targets.
Markers and Annotations
Marker places a predefined pin. Annotation places any SwiftUI view at a coordinate. Other
MapContent types include MapCircle, MapPolygon, MapPolyline, and UserAnnotation.
import MapKit
import SwiftUI
Map {
Annotation("Seattle", coordinate: .seattle) {
Image(systemName: "mappin")
.foregroundStyle(.black)
.padding()
.background(.red)
.clipShape(Circle())
}
Marker(coordinate: .newYork) {
Label("New York", systemImage: "mappin")
}
Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco)
}
Initial Camera Position
Map(initialPosition:) takes a MapCameraPosition. Build one from userLocation (with a
fallback), or from the camera, region, rect, or item static functions. The default is
automatic, which fits the map content.
let initialPosition: MapCameraPosition = .userLocation(
fallback: .camera(
MapCamera(centerCoordinate: .newYork, distance: 0)
)
)
Map(initialPosition: initialPosition) {
// markers
}
Binding the Camera
For continuous control, pass a binding. SwiftUI writes to it when the user drags the map, and moves the camera when your code sets the property.
@State private var position: MapCameraPosition = .userLocation(
fallback: .camera(MapCamera(centerCoordinate: .newYork, distance: 0))
)
Map(position: $position) { /* content */ }
Restricting Interactions
The interactionModes parameter limits what the user can do. MapInteractionModes covers pan,
pitch, rotate, and zoom; all are enabled by default.
Map(position: $position, interactionModes: .pitch) { /* content */ }