Animations

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 Android 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.

Note

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.

Animation types

The Maps SDK provides high-level, mid-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 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 built-in animation types are:

  • flyTo 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.
  • easeTo gradually changes the camera's position with an animated transition from the old values to the new values.
  • rotateBy rotates the map to a different bearing with an animated transition.
  • scaleBy animates a change in the size of the images on the map.
  • pitchBy animates a change in the pitch of the map.
  • moveBy instantaneously re-positions the camera with a quick animated transition from the old values to the new values.

You can call these functions with the MapboxMap object. Different parameters will be used depending on the function type, but all these functions support customizing the animation duration and interpolator.

It's important to 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.

example
Fly-to camera animation

Animate the camera changes with the fly-to animation. This causes the camera to ease from a starting point to an end destination.

Mid-level animation APIs

There are several mid-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.

Any number of animators extending CameraAnimator can be created and started either sequentially or in parallel. In that case, you do not need to register and unregister those animators.

Low-level animation APIs

The Maps SDK also has a set of low-level animation APIs. Each camera property can be animated independently through the Android SDK animator framework.

With the low-level animation APIs, any number of animators extending CameraAnimator can be created, but you must also register them in the CameraAnimationsPlugin for the map camera to work properly and unregister them when they are no longer needed. You drive the animation lifecycle (start, end, and cancel) directly with the low-level animation API.

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 call mapboxMap.easeTo(cameraOptions, mapAnimationOptions).

Start a mid-level animation event

To start camera animations created using the mid-level animation APIs, use CameraAnimationsPlugin.playAnimatorsTogether (to run the animations at the same time) or CameraAnimationsPlugin.playAnimatorsSequentially (to run the animations one by one).

This example runs an animation set that consists of bearing and pitch animators executing simultaneously. It's important to note that the bearing and pitch animator objects cannot be reused later without explicit registration, since the playAnimatorsTogether function registers them on animation start and unregisters them on animation end or on cancel.

import com.mapbox.maps.plugin.animation.CameraAnimatorOptions.Companion.cameraAnimatorOptions

mapView.camera.apply {
    val bearing = createBearingAnimator(cameraAnimatorOptions(18.0, 20.0) { startValue = 15.0 }) {
          duration = 8500
          interpolator = AnticipateOvershootInterpolator()
    }
    val pitch = createPitchAnimator(cameraAnimatorOptions(30.0) { startValue = 15.0 }) {
          duration = 2000
    }
    playAnimatorsTogether(bearing, pitch)
}
example
Start camera animations sequentially

Use playAnimatorsSequentially to update the camera's zoom, pitch, and bearing in sequence.

Start a low-level animation event

example
Using custom camera animations

Animate the map camera to a new position using camera animators. Individual camera properties such as zoom, bearing, and center coordinate can be animated independently.

With the low-level animation APIs, any number of animators extending CameraAnimator can be created, but you must also register them in Mapbox Maps Animation Plugin for the map camera to work properly and unregister them when they are no longer needed. You drive the animation lifecycle (start, end, and cancel) directly with the low-level animation API.

To start camera animations created using the low-level animation APIs, use the CameraAnimator.start method. In order for the animator to start, you need to register it first using CameraAnimationsPlugin.registerAnimators.

This example constructs three independent animations (bearing, zoom, and pitch) and creates an animation set so they execute simultaneously. The animation can be customized by using the flexible low-level APIs.

import com.mapbox.maps.plugin.animation.CameraAnimatorOptions.Companion.cameraAnimatorOptions

val plugin = mapView.camera
val bearing = plugin.createBearingAnimator(cameraAnimatorOptions(160.0) { startValue = 0.0 }) {
      duration = 8500
      interpolator = AnticipateOvershootInterpolator()
}
plugin.registerAnimators(bearing)
bearing.apply {
    addListener(
        object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator?) {}

            override fun onAnimationEnd(animation: Animator?) {
              (animation as? CameraAnimator<*>)?.let {
                plugin.unregisterAnimators(it)
              }
            }

            override fun onAnimationCancel(animation: Animator?) {
              (animation as? CameraAnimator<*>)?.let {
                plugin.unregisterAnimators(it)
              }
            }

            override fun onAnimationRepeat(animation: Animator?) {}
        }
    )
    start()
}
example
Low-level animation API event

Use the CameraOperator.start method to start a new animation that changes the camera's pitch.

Listen for camera animation events

The Maps SDK provides camera animation event listeners that can tell you if a specific event has happened or if any camera animation events have happened. The possible events are:

  • The animation is about to start
  • The animation is about to interrupt an already-running animation of the same type
  • The animation is to end
  • The animation is about to be canceled

Listen for high-level animation API events

If you are using the high-level animations APIs and want to listen to the whole high-level animation as one instance, provide animatorListener as part of MapAnimationOptions when starting the animation.

mapboxMap.flyTo(
  cameraOptions,
  mapAnimationOptions {
    animatorListener(object : Animator.AnimatorListener {
      override fun onAnimationStart(animation: Animator?) {
        // code to be invoked when animation starts
      }

      override fun onAnimationEnd(animation: Animator?) {
        // code to be invoked when animation ends
      }

      override fun onAnimationCancel(animation: Animator?) {
        // code to be invoked when animation is canceled
      }

      override fun onAnimationRepeat(animation: Animator?) {
        // code to be invoked when animation repeats
      }
    })
  }
)

Listen for lower-level animation API events

If you are using the mid-level or low-level animation APIs and want to listen to a specific event, or all events, you can add the regular Android SDK listener as CameraAnimator.addListener(listener: AnimatorListener) to any CameraAnimator, which extends Android's ValueAnimator with all existing functionality.

lowOrMidLevelAnimator.addListener(
    object : Animator.AnimatorListener {
        override fun onAnimationStart(animation: Animator?) {
          // code to be invoked when animation starts
        }
        override fun onAnimationEnd(animation: Animator?) {
          // code to be invoked when animation ends
        }
        override fun onAnimationCancel(animation: Animator?) {
          // code to be invoked when animation is canceled
        }
        override fun onAnimationRepeat(animation: Animator?) {
          // code to be invoked when animation repeats
        }
    }
)

Listen for all animation events

If you want to listen to all events happening to the overall camera animation system, use CameraAnimationsPlugin .addCameraAnimationsLifecycleListener(listener: CameraAnimationsLifecycleListener). It will report all the logic when an animator of any type (low-level, mid-level, and high-level animation APIs) is about to start, stop, be canceled, or be interrupted. Register the listener using CameraAnimationsPlugin.addCameraAnimationsLifecycleListener and unregister it using CameraAnimationsPlugin.removeCameraAnimationsLifecycleListener.

Listen for specific animation value change events

The Maps SDK CameraAnimationsPlugin also provides methods to listen to specific value change events: