Skip to main content


Camera animations are the means by which camera settings are changed from old values to new values over a period of time. The Maps SDK for iOS provides expressive ways of controlling animations. You can animate the camera to move to a new center location and to update the bearing, pitch, zoom, padding, and anchor. Each of these camera properties can be animated independently through the Maps SDK camera animation system.


Only one animation instance per camera setting type can run at a time. For example, if an animator that changes the camera's bearing is running, then starting another bearing operator at the same time will cancel the first one and then start running. This prevents the map from jumping between two or more animators of the same type. The code in the completion block will be called upon the animation's cancellation.

Animation types

The Maps SDK provides high-level and low-level animation APIs that allow you to transition the camera from old values to new values.

Using animations to change camera values

If you use MapboxMap.setCamera(to:) to change camera values instead of using an animator, the camera position will change abruptly to the new values instead of an animated change.

High-level animation APIs

The Maps SDK has a set of ready-to-use functions for animating map camera transitions. These high-level APIs allow you to implement animations quickly, but have limited options for customization. The Maps SDK provides a few built-in animation types:

  • fly(to:duration:completion:) changes the camera's position from the old values to the new values using a combination of zooming and panning in an animated transition that evokes flight.
  • ease(to:duration:curve:completion: gradually changes the camera's position with an animated transition from the old values to the new values.

Note that only one high-level animation can run at a time. If a high-level animation starts while another high-level animation is already running, the running animation will be canceled even if the new high-level animation only changes map camera parameters the running one does not use. The code in the completion block will be called upon the animation's cancellation.

Low-level animation APIs

There are several lower-level animation APIs that you can use to implement animations with more customization options including running multiple animations simultaneously. These APIs offer more flexibility, but require writing more custom code.

The CameraAnimatorManager exposes a set of makeAnimator* functions that allow you to create other animations by setting new values for the camera position options. The following example shows how you could create an experience in which the map rotates and zooms at the same time:

let animator = 5, curve: .easeInOut) { transition in
// Transition the zoom level of the map's camera to `7`
transition.zoom.toValue = 7

// Transition the bearing of the map's camera to `180` degrees
transition.bearing.toValue = 180

In the above scenario, transition is a CameraTransition object. This object is passed into every animation block, allowing you to control both where the animation completes (in other words, the final map camera) and its starting position.

Start a camera animation

Start a high-level animation event

Camera animations created using the high-level animations APIs start automatically when they are called. For example, the camera animation will start after you define new CameraOptions and call ease(to:), and will take 5 seconds to complete:

// Center the map camera over New York City.
let centerCoordinate = CLLocationCoordinate2D(latitude: 40.7128, longitude: -74.0060)

let newCamera = CameraOptions(
center: centerCoordinate,
padding: .zero,
anchor: .zero,
zoom: 7.0,
bearing: 180.0,
pitch: 15.0) newCamera, duration: 5.0)
Use camera animations

Use ease(to:) to animate updates to the camera's position.


Start a low-level animation event

To start a camera animation created using the low-level animation APIs, use the BasicCameraAnimator.startAnimation() method. For example, to start the animation defined in the low-level animation APIs section above:

let animator = 4, curve: .easeOut) { transition in
transition.zoom.toValue = 10

Use custom camera animations

Use the BasicCameraAnimator.startAnimation() method to start new animations for several camera properties.


Chaining animations

With BasicCameraAnimator.addCompletion(_:), you can add a completion block to be invoked when the animation is finished.

animator.addCompletion { position in
print("Animation complete at position: \(position)")

These completion blocks can be used to chain animations to execute one after another, as shown in this example:

// Declare an animator that changes the map's
let bearingAnimator = 4, curve: .easeInOut) { transition in
transition.bearing.toValue = -45

bearingAnimator.addCompletion { (_) in
print("All animations complete!")

// Declare an animator that changes the map's pitch.
let pitchAnimator = 2, curve: .easeInOut) { transition in
transition.pitch.toValue = 55

// Begin the bearing animation once the pitch animation has finished.
pitchAnimator.addCompletion { _ in
print("Animating camera bearing from 0 degrees -> 45 degrees")

// Declare an animator that changes the map's zoom level.
let zoomAnimator = 4, curve: .easeInOut) { transition in
transition.zoom.toValue = 14

// Begin the pitch animation once the zoom animation has finished.
zoomAnimator.addCompletion { _ in
print("Animating camera pitch from 0 degrees -> 55 degrees")

// Begin the zoom animation.
zoomAnimator.startAnimation(afterDelay: 1)

Animation owner

AnimationOwner is a struct used to keep track of the source (or owner) for each animation. AnimationOwner has the following predefined values:

  • gestures: support for animations run by gestures
  • unspecified: support for a non-specific animation

Custom AnimationOwner can be created using AnimationOwner(rawValue:).

Listen for camera animation events

To check whether an animation is in progress, you can use MapboxMap.onCameraChanged. Note that this can also be called for camera changes triggered by gestures and can be called hundreds of times as the camera changes, so implementations using it should be lightweight.

mapView.mapboxMap.onCameraChanged.observe { context in
let cameraState = context.cameraState
}.store(in: &cancellables) // add to dispose bag

To check whether an individual animator is running, use BasicCameraAnimator.isRunning.

To execute code after a camera animation is finished, use the camera animation's completion block as describe in Chaining animations.

Was this page helpful?