Created
April 15, 2021 15:10
-
-
Save halilozercan/b0a77f430f8806751d6449eaa0988607 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Composable | |
fun <T: Comparable<T>> SlideInOutLayout( | |
targetState: T, | |
modifier: Modifier = Modifier, | |
animationSpec: FiniteAnimationSpec<Float> = tween(), | |
content: @Composable (T) -> Unit | |
) { | |
val items = remember { mutableStateListOf<CrossSlideAnimationItem<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) } | |
} else { | |
this | |
} | |
} | |
items.clear() | |
keys.mapTo(items) { key -> | |
CrossSlideAnimationItem(key) { | |
val visibility = transition.animateFloat( | |
transitionSpec = { animationSpec } | |
) { | |
when { | |
it == key -> 0f | |
it > key -> -1f | |
else -> 1f | |
} | |
} | |
Box(Modifier.then(PercentageLayoutOffset(rawOffset = visibility))) { | |
content(key) | |
} | |
} | |
} | |
} else if (transitionState.currentState == transitionState.targetState) { | |
// Remove all the intermediate items from the list once the animation is finished. | |
items.removeAll { it.key != transitionState.targetState } | |
} | |
Box(modifier) { | |
items.forEach { | |
key(it.key) { | |
it.content() | |
} | |
} | |
} | |
} | |
data class CrossSlideAnimationItem<T>( | |
val key: T, | |
val content: @Composable () -> Unit | |
) | |
// Taken from https://github.com/zach-klippenstein/compose-backstack | |
class PercentageLayoutOffset(private val rawOffset: State<Float>) : LayoutModifier { | |
private val offset = { rawOffset.value.coerceIn(-1f..1f) } | |
override fun MeasureScope.measure( | |
measurable: Measurable, | |
constraints: Constraints | |
): MeasureResult { | |
val placeable = measurable.measure(constraints) | |
return layout(placeable.width, placeable.height) { | |
placeable.place(offsetPosition(IntSize(placeable.width, placeable.height))) | |
} | |
} | |
private fun offsetPosition(containerSize: IntSize) = IntOffset( | |
// RTL is handled automatically by place. | |
x = (containerSize.width * offset()).toInt(), | |
y = 0 | |
) | |
override fun toString(): String = "${this::class.java.simpleName}(offset=$offset)" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment