Three iOS 17 MapKit modifiers cover map interactivity: onMapCameraChange observes the camera
while the user drags, mapCameraKeyframeAnimator animates the camera along keyframes, and the
selection binding makes markers selectable.
Observing the Camera
Watching the position binding with onChange does not report the camera during a user drag. Use
onMapCameraChange: its closure receives a MapCameraUpdateContext with the current camera,
region, and rect.
Map(position: $position) { /* markers */ }
.onMapCameraChange(frequency: .continuous) { context in
print(context.camera)
print(context.region)
print(context.rect)
}
MapCameraUpdateFrequency has two cases: continuous reports in near real time, onEnd fires
once when the drag finishes. Pick onEnd for expensive work such as refetching pins.
Animating the Camera
mapCameraKeyframeAnimator runs a keyframe animation on the camera whenever its trigger value
changes. Every MapCamera property is animatable through KeyframeTrack, and the builder hands
you the camera's value before the animation starts.
.mapCameraKeyframeAnimator(trigger: trigger) { camera in
KeyframeTrack(\MapCamera.centerCoordinate) {
LinearKeyframe(.newYork, duration: 2)
LinearKeyframe(.seattle, duration: 2)
LinearKeyframe(.sanFrancisco, duration: 2)
}
KeyframeTrack(\MapCamera.distance) {
LinearKeyframe(camera.distance, duration: 2)
LinearKeyframe(camera.distance * 2, duration: 2)
LinearKeyframe(camera.distance, duration: 2)
}
}
Selecting Markers
Pass a selection binding to the Map initializer and tag each marker. The selection type must
match the tag type, or nothing selects.
@State private var selection: Int?
Map(position: $position, selection: $selection) {
Marker("New York", monogram: Text("NY"), coordinate: .newYork).tag(1)
Marker("Seattle", monogram: Text("SE"), coordinate: .seattle).tag(2)
Marker("San Francisco", monogram: Text("SF"), coordinate: .sanFrancisco).tag(3)
}
.onChange(of: selection) {
print("selection changed:", selection as Any)
}