Interactivity powered by state machines
DotLottie Android supports interactive animations with state machines for advanced user interactions. State machines allow you to create dynamic animations that respond to user input, gestures, and other events.
Creation
Learn how to create dotLotties with state machines here.
Loading State Machines
You can load state machines from .lottie files or from JSON data:
// Load state machine by ID from .lottie filedotLottieAnimationView.stateMachineLoad("state_machine_id")
// Or load state machine from JSON datadotLottieAnimationView.stateMachineLoadData(stateMachineJsonData)
// Start the state machinedotLottieAnimationView.stateMachineStart()
Usage
The following example demonstrates how to use a state machine with a Lottie animation in a Composable function. The state machine is controlled by a DotLottieController, which is used to load the state machine, start and stop it, and post events to it. The controller also provides a listener for state machine events.
Exploding Pigeon example
@Composablefun StateMachineExample() { // Controller for the DotLottieAnimation composable val controller = remember { DotLottieController() }
// Listener for the state machine events val stateListener = remember { object : StateMachineEventListener { // Logs the transition from one state to another override fun onTransition(previousState: String, newState: String) { Log.i("DotLottie", "Transition: $previousState -> $newState") }
// Logs when a state is exited override fun onStateExit(leavingState: String) { Log.i("DotLottie", "Exit: $leavingState") }
// Logs when a state is entered override fun onStateEntered(enteringState: String) { Log.i("DotLottie", "Enter: $enteringState") } } }
// Adds the state machine event listener to the controller LaunchedEffect(UInt) { controller.addStateMachineEventListener(stateListener) }
Column( modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { Row { DotLottieAnimation( source = DotLottieSource.Asset("exploding_pigeon.lottie"), autoplay = true, loop = false, controller = controller, ) } Row { Column { // Button to load and start the state machine Button(onClick = { val result = controller.stateMachineLoad("pigeon_fsm") if (result) { controller.stateMachineStart() } }) { Text(text = "State Machine") }
// Button to fire an "explosion" event to the state machine. You can also bind this to a gesture or other event. Button(onClick = { controller.stateMachineFireEvent("explosion") }) { Text(text = "Explosion") }
// Button to stop the state machine Button(onClick = { controller.stateMachineStop() }) { Text(text = "Stop") } } } }}
Exploding Pigeon state machine
{ "descriptor": { "id": "pigeon_fsm", "initial": 0 }, "states": [ { "name": "pigeon", "type": "PlaybackState", "mode": "Forward", "speed": 1, "use_frame_interpolation": true, "autoplay": true, "loop": true, "marker": "bird" }, { "name": "explosion", "type": "PlaybackState", "mode": "Forward", "autoplay": true, "speed": 0.5, "loop": false, "marker": "explosion" }, { "name": "feathers", "type": "PlaybackState", "autoplay": true, "speed": 1, "loop": false, "marker": "feathers" } ], "transitions": [ { "type": "Transition", "from_state": 0, "to_state": 1, "string_event": { "value": "explosion" } }, { "type": "Transition", "from_state": 1, "to_state": 2, "on_complete_event": {} }, { "type": "Transition", "from_state": 2, "to_state": 0, "on_complete_event": {} } ], ...}
How it works
- The state machine has three states:
pigeon
,explosion
, andfeathers
. - The state machine starts in the
pigeon
state. - When the
explosion
event is fired to the state machine, it transitions to theexplosion
state. - When the
explosion
state completes, it transitions to thefeathers
state. - When the
feathers
state completes, it transitions back to thepigeon
state.
State Machine Events
Monitor state machine events by implementing StateMachineEventListener
:
private val stateMachineListener = object : StateMachineEventListener { override fun onStart() { Log.d(TAG, "State machine started") }
override fun onStop() { Log.d(TAG, "State machine stopped") }
override fun onStateEntered(enteringState: String) { Log.d(TAG, "Entered state: $enteringState") }
override fun onStateExit(leavingState: String) { Log.d(TAG, "Exited state: $leavingState") }
override fun onTransition(previousState: String, newState: String) { Log.d(TAG, "Transitioned from $previousState to $newState") }
override fun onNumericInputValueChange(inputName: String, oldValue: Float, newValue: Float) { Log.d(TAG, "Input $inputName changed from $oldValue to $newValue") }
override fun onStringInputValueChange(inputName: String, oldValue: String, newValue: String) { Log.d(TAG, "Input $inputName changed from $oldValue to $newValue") }
override fun onBooleanInputValueChange(inputName: String, oldValue: Boolean, newValue: Boolean) { Log.d(TAG, "Input $inputName changed from $oldValue to $newValue") }
override fun onInputFired(inputName: String) { Log.d(TAG, "Input fired: $inputName") }
override fun onCustomEvent(message: String) { Log.d(TAG, "Custom event: $message") }
override fun onError(message: String) { Log.e(TAG, "State machine error: $message") }}
// Add the listenerdotLottieAnimationView.addStateMachineEventListener(stateMachineListener)
State Machine Input Controls
State machines can have various types of inputs that you can control programmatically:
// Set input valuesdotLottieAnimationView.stateMachineSetNumericInput("inputName", 42.0f)dotLottieAnimationView.stateMachineSetStringInput("inputName", "value")dotLottieAnimationView.stateMachineSetBooleanInput("inputName", true)
// Get input valuesval numericValue = dotLottieAnimationView.stateMachineGetNumericInput("inputName")val stringValue = dotLottieAnimationView.stateMachineGetStringInput("inputName")val booleanValue = dotLottieAnimationView.stateMachineGetBooleanInput("inputName")
// Fire eventsdotLottieAnimationView.stateMachineFireEvent("eventName")
// Get current stateval currentState = dotLottieAnimationView.stateMachineCurrentState()
// Stop state machinedotLottieAnimationView.stateMachineStop()
Advanced State Machine Features
Gesture Events
You can post gesture events directly to the state machine:
// For traditional UIdotLottieAnimationView.stateMachinePostEvent(Event.Click(x, y))
// For Jetpack Composecontroller.stateMachinePostEvent(Event.Click(x, y))
URL Policy
When starting a state machine, you can specify a URL policy and callback:
dotLottieAnimationView.stateMachineStart(OpenUrlPolicy, { url -> // Handle URL opening})