I'm developing a SwiftUI app with Mapbox. How can I add zoom buttons to my map?
My current code that works in the .camera
viewport state. But how can I apply zoom when the viewport is in the .idle
state? Is there a common solution for any state?
Please note that this question relates only to the Mapbox for SwiftUI iOS SDK, not Apple MapKit or any other map SDK.
.overlay(alignment: .trailing) {
Button {
guard
let cam = viewport.camera,
let zoom = cam.zoom
else { return }
// Compute new zoom level (clamped)
let newZoom = min(zoom + 1, 20)
// Animate the viewport change
withViewportAnimation {
viewport = .camera(
center: cam.center,
zoom: newZoom,
bearing: cam.bearing,
pitch: cam.pitch
)
}
} label: {
Image(systemName: "plus")
}
.buttonStyle(MapFloatingButtonStyle())
}
You are using the wrong technique to get the current zoom level of the map. Viewport.camera.zoom
doesn't hold the current zoom level, it holds the last value you tried to set when changing viewport to .camera()
. So, your code will work when the map first loads, but if the user interacts with the map, viewport.isIdle
becomes true (and viewport.camera
no longer exists), and the next button press will return early due to your guard.
What you want to do is get ahold of the MapboxMap
instance, where you can read MapboxMap.cameraState.zoom
. This is the actual current zoom of the map's camera.
Button(action: {
let zoom = self.map?.cameraState.zoom ?? 0
let newZoom = min(zoom + 1, 20)
withViewportAnimation {
viewport = .camera(zoom: newZoom)
}
})
In this case, self.map
exists because I set it in Map.onMapLoaded()
.
MapReader { proxy in
Map(viewport: $viewport)
.mapStyle(.streets)
.onMapLoaded { _ in
self.map = proxy.map
}
}