All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.androidx.compose.animation.BoundsAnimation.kt Maven / Gradle / Ivy

There is a newer version: 1.8.0-alpha01
Show newest version
/*
 * Copyright 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.compose.animation

import androidx.compose.animation.core.AnimationVector4D
import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.geometry.Rect

@ExperimentalSharedTransitionApi
internal class BoundsAnimation(
    val transitionScope: SharedTransitionScope,
    val transition: Transition,
    animation: Transition.DeferredAnimation,
    boundsTransform: BoundsTransform
) {
    var animation: Transition.DeferredAnimation
        by mutableStateOf(animation)
        private set

    fun updateAnimation(
        animation: Transition.DeferredAnimation,
        boundsTransform: BoundsTransform,
    ) {
        if (this.animation != animation) {
            this.animation = animation
            animationState = null
            animationSpec = DefaultBoundsAnimation
        }
        this.boundsTransform = boundsTransform
    }

    private var boundsTransform: BoundsTransform by mutableStateOf(boundsTransform)

    val isRunning: Boolean
        get() {
            var parent: Transition<*> = transition
            while (parent.parentTransition != null) {
                parent = parent.parentTransition!!
            }
            return parent.currentState != parent.targetState
        }

    var animationSpec: FiniteAnimationSpec = DefaultBoundsAnimation

    // It's important to back this state up by a mutable state, so that whoever read it when
    // it was null will get an invalidation when it's set.
    var animationState: State? by mutableStateOf(null)
    val value: Rect?
        get() = if (transitionScope.isTransitionActive) {
            animationState?.value
        } else {
            null
        }

    fun animate(currentBounds: Rect, targetBounds: Rect) {
        if (transitionScope.isTransitionActive) {
            if (animationState == null) {
                // Only invoke bounds transform when animation is initialized. This means
                // boundsTransform will not participate in interruption-handling animations.
                animationSpec = boundsTransform.transform(currentBounds, targetBounds)
            }
            animationState = animation.animate(transitionSpec = { animationSpec }) {
                if (it == transition.targetState) {
                    // its own bounds
                    targetBounds
                } else {
                    currentBounds
                }
            }
        }
    }

    val target: Boolean get() = transition.targetState
}

private val DefaultBoundsAnimation = spring(
    stiffness = Spring.StiffnessMediumLow,
    visibilityThreshold = Rect.VisibilityThreshold
)




© 2015 - 2025 Weber Informatics LLC | Privacy Policy