() -> Unit ) @Composable fun <T> Crossfade( targetState: T, modifier: Modifier = Modifier, animationSpec: FiniteAnimationSpec<Float> = tween(), content: @Composable (T) -> Unit ) { val items = remember { mutableStateListOf<CrossfadeAnimationItem<T>>() } val transitionState = remember { MutableTransitionState(targetState) } val targetChanged = (targetState != transitionState.targetState) transitionState.targetState = targetState val transition = updateTransition(transitionState) if (targetChanged || items.isEmpty()) { // Only manipulate the list when the state is changed, or in the first run. val keys = items.map { it.key }.run { if (!contains(targetState)) { toMutableList().also { it.add(targetState) }
() -> Unit ) @Composable fun <T> Crossfade( targetState: T, modifier: Modifier = Modifier, animationSpec: FiniteAnimationSpec<Float> = tween(), content: @Composable (T) -> Unit ) { val items = remember { mutableStateListOf<CrossfadeAnimationItem<T>>() } val transitionState = remember { MutableTransitionState(targetState) } val targetChanged = (targetState != transitionState.targetState) transitionState.targetState = targetState val transition = updateTransition(transitionState) if (targetChanged || items.isEmpty()) { // Only manipulate the list when the state is changed, or in the first run. val keys = items.map { it.key }.run { if (!contains(targetState)) { toMutableList().also { it.add(targetState) }
() -> Unit ) @Composable fun <T> Crossfade( targetState: T, modifier: Modifier = Modifier, animationSpec: FiniteAnimationSpec<Float> = tween(), content: @Composable (T) -> Unit ) { val items = remember { mutableStateListOf<CrossfadeAnimationItem<T>>() } val transitionState = remember { MutableTransitionState(targetState) } val targetChanged = (targetState != transitionState.targetState) transitionState.targetState = targetState val transition = updateTransition(transitionState) if (targetChanged || items.isEmpty()) { // Only manipulate the list when the state is changed, or in the first run. val keys = items.map { it.key }.run { if (!contains(targetState)) { toMutableList().also { it.add(targetState) }
() -> Unit ) @Composable fun <T> Crossfade( targetState: T, modifier: Modifier = Modifier, animationSpec: FiniteAnimationSpec<Float> = tween(), content: @Composable (T) -> Unit ) { val items = remember { mutableStateListOf<CrossfadeAnimationItem<T>>() } val transitionState = remember { MutableTransitionState(targetState) } val targetChanged = (targetState != transitionState.targetState) transitionState.targetState = targetState val transition = updateTransition(transitionState) if (targetChanged || items.isEmpty()) { // Only manipulate the list when the state is changed, or in the first run. val keys = items.map { it.key }.run { if (!contains(targetState)) { toMutableList().also { it.add(targetState) }
transitionState = remember { MutableTransitionState(targetState) } val targetChanged = (targetState != transitionState.targetState) transitionState.targetState = targetState val transition = updateTransition(transitionState) if (targetChanged || items.isEmpty()) { // Only manipulate the list when the state is changed, or in the first run. val keys = items.map { it.key }.run { if (!contains(targetState)) { toMutableList().also { it.add(targetState) } } else { this } } items.clear() keys.mapTo(items) { key -> CrossfadeAnimationItem(key) { val alpha by transition.animateFloat( transitionSpec = { animationSpec } ) { if (it == key) 1f else 0f } Box(Modifier.graphicsLayer { this.alpha = alpha }) { content(key) }
효과를 구현할 수 있습니다. - 화면 전환 효과를 구현할 때는 각각의 화면을 Box로 한번 감싼 후, Box의 modifier 속성에 변화를 주면 됩니다. - Saveable, SaveableStateHolder - 화면을 전환할 때는 마지막 상태를 저장해두고, 다시 되돌아왔을 때 상태를 복구해줘야 합니다. - ViewModel에 상태를 저장해두는 방법도 가능합니다. - 다만 스크롤 같은 UI 상태를 저장/복구하려면, SaveableStateHolder를 이용하는 것이 간단합니다. - 참고로 navigation-compose 라이브러리가 공식적으로 제공되고 있는데요. 내부적으로 SaveableStateHolder를 사용하고 있습니다.
View 기반의 Material Motion에서는 Container Transform가 Shared Elements를 기반으로 구현되어 있습니다. - Compose는 Shared Elements가 없기 때문에 Container 간의 Transition을 구현하려면, (@Composable을 따로 받는다던지) 약간의 trick이 필요할 것 같습니다. - 🤔🤔🤔