---
title: "Animatable"
description: "[Animatable] is a value holder that automatically animates its value when the value is changed
via [animateTo]. If [animateTo] is invoked during an ongoing value change animation, a new
animation will transition [Animatable] from its current value (i.e. value at the point of
interruption) to the new [targetValue]. This ensures that the value change is __always__
continuous using [animateTo]. If a [spring] animation (e.g. default animation) is used with
[animateTo], the velocity change will guarantee to be continuous as well.

Unlike [AnimationState], [Animatable] ensures *mutual exclusiveness* on its animations. To
achieve this, when a new animation is started via [animateTo] (or [animateDecay]), any ongoing
animation will be canceled via a [CancellationException]."
type: "class"
---

<div class='type'>Class</div>


<a id='references'></a>

<div class='sourceset sourceset-common'>Common</div>


```kotlin
public class Animatable<T, V : AnimationVector>
@RememberInComposition
constructor(
    initialValue: T,
    public val typeConverter: TwoWayConverter<T, V>,
    private val visibilityThreshold: T? = null,
    public val label: String = "Animatable",
)
```


`Animatable` is a value holder that automatically animates its value when the value is changed
via `animateTo`. If `animateTo` is invoked during an ongoing value change animation, a new
animation will transition `Animatable` from its current value (i.e. value at the point of
interruption) to the new `targetValue`. This ensures that the value change is __always__
continuous using `animateTo`. If a `spring` animation (e.g. default animation) is used with
`animateTo`, the velocity change will guarantee to be continuous as well.

Unlike `AnimationState`, `Animatable` ensures *mutual exclusiveness* on its animations. To
achieve this, when a new animation is started via `animateTo` (or `animateDecay`), any ongoing
animation will be canceled via a `CancellationException`.

#### Parameters

| | |
| --- | --- |
| initialValue | initial value of the animatable value holder |
| typeConverter | A two-way converter that converts the given type `T` from and to `AnimationVector` |
| visibilityThreshold | Threshold at which the animation may round off to its target value. |
| label | An optional label for differentiating this animation from others in android studio. |



## Secondary Constructors

```kotlin
public constructor(
    initialValue: T,
    typeConverter: TwoWayConverter<T, V>,
    visibilityThreshold: T? = null,
) : this(initialValue, typeConverter, visibilityThreshold, "Animatable")
```

## Functions

```kotlin
public fun updateBounds(lowerBound: T? = this.lowerBound, upperBound: T? = this.upperBound)
```


Updates either `lowerBound` or `upperBound`, or both. This will update
`Animatable.lowerBound` and/or `Animatable.upperBound` accordingly after a check to ensure
the provided `lowerBound` is no greater than `upperBound` in any dimension.

Setting the bounds will immediate clamp the `value`, only if the animation isn't running. For
the on-going animation, the value at the next frame update will be checked against the
bounds. If the value reaches the bound, then the animation will end with `BoundReached` end
reason.

#### Parameters

| | |
| --- | --- |
| lowerBound | lower bound of the animation. Defaults to the `Animatable.lowerBound` that is currently set. |
| upperBound | upper bound of the animation. Defaults to the `Animatable.upperBound` that is currently set. |



```kotlin
public suspend fun animateTo(
        targetValue: T,
        animationSpec: AnimationSpec<T> = defaultSpringSpec,
        initialVelocity: T = velocity,
        block: (Animatable<T, V>.() -> Unit)? = null,
    ): AnimationResult<T, V>
```


Starts an animation to animate from `value` to the provided `targetValue`. If there is
already an animation in-flight, this method will cancel the ongoing animation before starting
a new animation continuing the current `value` and `velocity`. It's recommended to set the
optional `initialVelocity` only when `animateTo` is used immediately after a fling. In most
of the other cases, altering velocity would result in visual discontinuity.

The animation will use the provided `animationSpec` to animate the value towards the
`targetValue`. When no `animationSpec` is specified, a `spring` will be used. `block` will be
invoked on each animation frame.

Returns an `AnimationResult` object. It contains: 1) the reason for ending the animation,
and 2) an end state of the animation. The reason for ending the animation can be either of
the following two:
- `Finished`, when the animation finishes successfully without any interruption,
- `BoundReached` If the animation reaches the either `lowerBound` or `upperBound` in any dimension, the animation will end with `BoundReached` being the end reason.

If the animation gets interrupted by 1) another call to start an animation (i.e.
`animateTo`/`animateDecay`), 2) `Animatable.stop`, or 3)`Animatable.snapTo`, the canceled
animation will throw a `CancellationException` as the job gets canceled. As a result, all the
subsequent work in the caller's coroutine will be canceled. This is often the desired
behavior. If there's any cleanup that needs to be done when an animation gets canceled,
consider starting the animation in a `try-catch` block.

__Note__: once the animation ends, its velocity will be reset to 0. The animation state at
the point of interruption/reaching bound is captured in the returned `AnimationResult`. If
there's a need to continue the momentum that the animation had before it was interrupted or
reached the bound, it's recommended to use the velocity in the returned
`AnimationResult.endState` to start another animation.


```kotlin
public suspend fun animateDecay(
        initialVelocity: T,
        animationSpec: DecayAnimationSpec<T>,
        block: (Animatable<T, V>.() -> Unit)? = null,
    ): AnimationResult<T, V>
```


Start a decay animation (i.e. an animation that *slows down* from the given `initialVelocity`
starting at current `Animatable.value` until the velocity reaches 0. If there's already an
ongoing animation, the animation in-flight will be immediately cancelled. Decay animation is
often used after a fling gesture.

`animationSpec` defines the decay animation that will be used for this animation. Some
options for this `animationSpec` include: `splineBasedDecay` and `exponentialDecay`. `block` will be invoked on each
animation frame.

Returns an `AnimationResult` object, that contains the `reason` for
ending the animation, and an end state of the animation. The reason for ending the animation
will be `Finished` if the animation finishes successfully without any interruption. If the
animation reaches the either `lowerBound` or `upperBound` in any dimension, the animation
will end with `BoundReached` being the end reason.

If the animation gets interrupted by 1) another call to start an animation (i.e.
`animateTo`/`animateDecay`), 2) `Animatable.stop`, or 3)`Animatable.snapTo`, the canceled
animation will throw a `CancellationException` as the job gets canceled. As a result, all the
subsequent work in the caller's coroutine will be canceled. This is often the desired
behavior. If there's any cleanup that needs to be done when an animation gets canceled,
consider starting the animation in a `try-catch` block.

__Note__, once the animation ends, its velocity will be reset to 0. If there's a need to
continue the momentum before the animation gets interrupted or reaches the bound, it's
recommended to use the velocity in the returned `AnimationResult.endState` to start another
animation.


```kotlin
public suspend fun snapTo(targetValue: T)
```


Sets the current value to the target value, without any animation. This will also cancel any
on-going animation with a `CancellationException`. This function will return *after*
canceling any on-going animation and updating the `Animatable.value` and
`Animatable.targetValue` to the provided `targetValue`.

__Note__: If the `lowerBound` or `upperBound` is specified, the provided `targetValue` will
be clamped to the bounds to ensure `Animatable.value` is always within bounds.

See `animateTo` and `animateDecay` for more details about animation being canceled.

#### Parameters

| | |
| --- | --- |
| targetValue | The new target value to set `value` to. |



```kotlin
public suspend fun stop()
```


Stops any on-going animation with a `CancellationException`.

This function will not return until the ongoing animation has been canceled (if any). Note,
`stop` function does **not** skip the animation value to its target value. Rather the
animation will be stopped in its track. Consider `snapTo` if it's desired to not only stop
the animation but also snap the `value` to a given value.

See `animateTo` and `animateDecay` for more details about animation being canceled.


```kotlin
public fun asState(): State<T>
```


Returns a `State` representing the current `value` of this animation. This allows hoisting
the animation's current value without causing unnecessary recompositions when the value
changes.



## Code Examples

### AnimatableAnimateToGenericsType
```kotlin
@Composable
fun AnimatableAnimateToGenericsType() {
    // Creates an `Animatable` to animate Offset and `remember` it.
    val animatedOffset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) }
    Box(
        Modifier.fillMaxSize().background(Color(0xffb99aff)).pointerInput(Unit) {
            coroutineScope {
                while (true) {
                    val offset = awaitPointerEventScope { awaitFirstDown().position }
                    // Launch a new coroutine for animation so the touch detection thread is not
                    // blocked.
                    launch {
                        // Animates to the pressed position, with the given animation spec.
                        animatedOffset.animateTo(
                            offset,
                            animationSpec = spring(stiffness = Spring.StiffnessLow),
                        )
                    }
                }
            }
        }
    ) {
        Text("Tap anywhere", Modifier.align(Alignment.Center))
        Box(
            Modifier.offset {
                    // Use the animated offset as the offset of the Box.
                    IntOffset(
                        animatedOffset.value.x.roundToInt(),
                        animatedOffset.value.y.roundToInt(),
                    )
                }
                .size(40.dp)
                .background(Color(0xff3c1361), CircleShape)
        )
    }
}
```

