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.
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.
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 interpolation.
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.
Animate the camera changes with the fly-to animation. This causes the camera to ease from a starting point to an end destination.
Showcase the camera animations based on MapViewportState
API
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.
MapEffect
, but it might break the MapViewportState
.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.
MapEffect
, but it might break the MapViewportState
.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)
, or mapViewportState.easeTo(cameraOptions, mapAnimationOptions)
in case of Jetpack Compose.
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)
}
Use playAnimatorsSequentially
to update the camera's zoom, pitch, and bearing in sequence.
Start a low-level animation event
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. 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()
}
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 the high level animation APIs, for example flyTo
when starting the animation.
mapboxMap.flyTo(
cameraOptions = cameraOptions,
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
}
}
)
val mapViewportState = rememberMapViewportState {
flyTo(cameraOptions = cameraOptions) { isFinished ->
// code to be invoked when animation ends, either with completion or cancellation
}
}
MapboxMap(
modifier = Modifier.fillMaxSize(),
mapViewportState = mapViewportState,
)
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 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:
- Change in center point:
CameraAnimationsPlugin.addCameraCenterChangeListener
- Change in bearing:
CameraAnimationsPlugin.addCameraBearingChangeListener
- Change in pitch:
CameraAnimationsPlugin.addCameraPitchChangeListener
- Change in zoom:
CameraAnimationsPlugin.addCameraZoomChangeListener
- Change in padding:
CameraAnimationsPlugin.addCameraPaddingChangeListener
- Change in anchor point:
CameraAnimationsPlugin.addCameraAnchorChangeListener