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

net.peanuuutz.fork.ui.foundation.animation.Crossfade.kt Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020 The Android Open Source Project
 * Modifications Copyright 2022 Peanuuutz
 *
 * 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 net.peanuuutz.fork.ui.foundation.animation

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import net.peanuuutz.fork.ui.animation.Transition
import net.peanuuutz.fork.ui.animation.animateFloat
import net.peanuuutz.fork.ui.animation.rememberUpdatedTransition
import net.peanuuutz.fork.ui.animation.spec.target.composite.FiniteAnimationSpec
import net.peanuuutz.fork.ui.animation.spec.target.composite.TweenSpec
import net.peanuuutz.fork.ui.foundation.layout.Box
import net.peanuuutz.fork.ui.ui.layout.Alignment
import net.peanuuutz.fork.ui.ui.modifier.Modifier
import net.peanuuutz.fork.ui.ui.modifier.draw.graphicsLayer

val DefaultCrossInterpolationAnimationSpec: FiniteAnimationSpec = TweenSpec()

@Composable
fun  Crossfade(
    targetState: T,
    modifier: Modifier = Modifier,
    animationSpec: FiniteAnimationSpec = DefaultCrossInterpolationAnimationSpec,
    contentAlignment: Alignment = Alignment.CenterOnPlane,
    contentKey: (state: T) -> Any? = { it },
    content: @Composable (state: T) -> Unit
) {
    val transition = rememberUpdatedTransition(targetState)
    transition.Crossfade(
        modifier = modifier,
        animationSpec = animationSpec,
        contentAlignment = contentAlignment,
        contentKey = contentKey,
        content = content
    )
}

@Composable
fun  Transition.Crossfade(
    modifier: Modifier = Modifier,
    animationSpec: FiniteAnimationSpec = DefaultCrossInterpolationAnimationSpec,
    contentAlignment: Alignment = Alignment.CenterOnPlane,
    contentKey: (state: T) -> Any? = { it },
    content: @Composable (state: T) -> Unit
) {
    val currentState = state
    val targetState = targetState
    val visibleStates = remember { mutableStateListOf(currentState) }
    if (currentState == targetState) {
        if (visibleStates.size > 1) {
            visibleStates.removeAll { it != targetState }
        }
        if (visibleStates.getOrNull(0) != targetState) {
            visibleStates.clear()
        }
    }
    if (targetState !in visibleStates) {
        val indexToReplace = visibleStates.indexOfFirst { state ->
            contentKey(state) == contentKey(targetState)
        }
        if (indexToReplace == -1) {
            visibleStates.add(targetState)
        } else {
            visibleStates[indexToReplace] = targetState
        }
    }

    Box(
        modifier = modifier,
        contentAlignment = contentAlignment
    ) {
        visibleStates.forEach { state ->
            key(contentKey(state)) {
                val alpha by animateFloat(
                    transitionSpec = { animationSpec }
                ) { candidateState ->
                    if (candidateState == state) 1.0f else 0.0f
                }

                Box(
                    modifier = Modifier.graphicsLayer {
                        this.alpha = alpha
                    }
                ) {
                    content(state)
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy