animateFloat

Functions summary

State<Float>
@Composable
InfiniteTransition.animateFloat(
    initialValue: Float,
    targetValue: Float,
    animationSpec: InfiniteRepeatableSpec<Float>,
    label: String
)

Creates an animation of Float type that runs infinitely as a part of the given InfiniteTransition.

Cmn
inline State<Float>
@Composable
<S : Any?> Transition<S>.animateFloat(
    noinline transitionSpec: @Composable Transition.Segment<S>.() -> FiniteAnimationSpec<Float>,
    label: String,
    targetValueByState: @Composable (state) -> Float
)

Creates a Float animation as a part of the given Transition.

Cmn

Functions

InfiniteTransition.animateFloat

@Composable
fun InfiniteTransition.animateFloat(
    initialValue: Float,
    targetValue: Float,
    animationSpec: InfiniteRepeatableSpec<Float>,
    label: String = "FloatAnimation"
): State<Float>

Creates an animation of Float type that runs infinitely as a part of the given InfiniteTransition.

Once the animation is created, it will run from initialValue to targetValue and repeat. Depending on the RepeatMode of the provided animationSpec, the animation could either restart after each iteration (i.e. RepeatMode.Restart), or reverse after each iteration (i.e . RepeatMode.Reverse).

If initialValue or targetValue is changed at any point during the animation, the animation will be restarted with the new initialValue and targetValue. Note: this means continuity will not be preserved.

A label for differentiating this animation from others in android studio.

import androidx.compose.animation.animateColor
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer

@Composable
fun InfinitelyPulsingHeart() {
    // Creates an [InfiniteTransition] instance for managing child animations.
    val infiniteTransition = rememberInfiniteTransition()

    // Creates a child animation of float type as a part of the [InfiniteTransition].
    val scale by
        infiniteTransition.animateFloat(
            initialValue = 3f,
            targetValue = 6f,
            animationSpec =
                infiniteRepeatable(
                    // Infinitely repeating a 1000ms tween animation using default easing curve.
                    animation = tween(1000),
                    // After each iteration of the animation (i.e. every 1000ms), the animation
                    // will
                    // start again from the [initialValue] defined above.
                    // This is the default [RepeatMode]. See [RepeatMode.Reverse] below for an
                    // alternative.
                    repeatMode = RepeatMode.Restart,
                ),
        )

    // Creates a Color animation as a part of the [InfiniteTransition].
    val color by
        infiniteTransition.animateColor(
            initialValue = Color.Red,
            targetValue = Color(0xff800000), // Dark Red
            animationSpec =
                infiniteRepeatable(
                    // Linearly interpolate between initialValue and targetValue every 1000ms.
                    animation = tween(1000, easing = LinearEasing),
                    // Once [TargetValue] is reached, starts the next iteration in reverse (i.e.
                    // from
                    // TargetValue to InitialValue). Then again from InitialValue to
                    // TargetValue. This
                    // [RepeatMode] ensures that the animation value is *always continuous*.
                    repeatMode = RepeatMode.Reverse,
                ),
        )

    Box(Modifier.fillMaxSize()) {
        Icon(
            Icons.Filled.Favorite,
            contentDescription = null,
            modifier =
                Modifier.align(Alignment.Center).graphicsLayer(scaleX = scale, scaleY = scale),
            tint = color,
        )
    }
}

Transition.animateFloat

@Composable
inline fun <S : Any?> Transition<S>.animateFloat(
    noinline transitionSpec: @Composable Transition.Segment<S>.() -> FiniteAnimationSpec<Float> = { spring() },
    label: String = "FloatAnimation",
    targetValueByState: @Composable (state) -> Float
): State<Float>

Creates a Float animation as a part of the given Transition. This means the states of this animation will be managed by the Transition.

targetValueByState is used as a mapping from a target state to the target value of this animation. Transition will be using this mapping to determine what value to target this animation towards. Note that targetValueByState is a composable function. This means the mapping function could access states, CompositionLocals, themes, etc. If the targetValue changes outside of a Transition run (i.e. when the Transition already reached its targetState), the Transition will start running again to ensure this animation reaches its new target smoothly.

An optional transitionSpec can be provided to specify (potentially different) animation for each pair of initialState and targetState. FiniteAnimationSpec includes any non-infinite animation, such as tween, spring, keyframes and even repeatable, but not infiniteRepeatable. By default, transitionSpec uses a spring animation for all transition destinations.

import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.keyframes
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.layout.Box
import androidx.compose.material.Button
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.graphicsLayer

// enum class ButtonStatus {Initial, Pressed, Released}
@Composable
fun AnimateAlphaAndScale(modifier: Modifier, transition: Transition<ButtonStatus>) {
    // Defines a float animation as a child animation of transition. This allows the
    // transition to manage the states of this animation. The returned State<Float> from the
    // [animateFloat] function is used here as a property delegate.
    // This float animation will use the default [spring] for all transition destinations, as
    // specified by the default `transitionSpec`.
    val scale: Float by
        transition.animateFloat { state -> if (state == ButtonStatus.Pressed) 1.2f else 1f }

    // Alternatively, we can specify different animation specs based on the initial state and
    // target state of the a transition run using `transitionSpec`.
    val alpha: Float by
        transition.animateFloat(
            transitionSpec = {
                when {
                    ButtonStatus.Initial isTransitioningTo ButtonStatus.Pressed -> {
                        keyframes {
                            durationMillis = 225
                            0f at 0 // optional
                            0.3f at 75
                            0.2f at 225 // optional
                        }
                    }
                    ButtonStatus.Pressed isTransitioningTo ButtonStatus.Released -> {
                        tween(durationMillis = 220)
                    }
                    else -> {
                        snap()
                    }
                }
            }
        ) { state ->
            // Same target value for Initial and Released states
            if (state == ButtonStatus.Pressed) 0.2f else 0f
        }

    Box(modifier.graphicsLayer(alpha = alpha, scaleX = scale)) {
        // content goes here
    }
}

label is used to differentiate from other animations in the same transition in Android Studio.

Returns
State<Float>

A State object, the value of which is updated by animation