Pavel Shnyakin
06/23/2023, 11:40 AMArkadii Ivanov
06/23/2023, 12:12 PMPavel Shnyakin
06/23/2023, 12:40 PMArkadii Ivanov
06/23/2023, 12:51 PMPavel Shnyakin
06/23/2023, 1:22 PMprivate fun Modifier.slideExitModifier(progress: Float, maxWidth: Dp): Modifier {
return offset {
IntOffset(x = (maxWidth * progress).roundToPx(), y = 0)
}
}
Arkadii Ivanov
06/23/2023, 1:44 PMthis
scope inside offset {}
.Pavel Shnyakin
06/23/2023, 1:45 PMprivate fun Modifier.slideExitModifier(progress: Float): Modifier {
return graphicsLayer {
translationX = size.width * progress
}
}
Arkadii Ivanov
06/23/2023, 1:46 PMPavel Shnyakin
06/23/2023, 2:31 PM@Composable
internal fun RootContent(
component: RootComponent,
modifier: Modifier = Modifier,
) {
Children(
stack = component.stack,
modifier = modifier,
animation = predictiveBackAnimation(
backHandler = component.backHandler,
exitModifier = { progress, _ ->
Modifier.slideExitModifier(
progress = progress,
)
},
enterModifier = { progress, _ ->
Modifier.slideEnterModifier(
progress = progress,
)
},
animation = stackAnimation(iosLikeSlide()),
onBack = component::onBackClicked,
),
) {
SomeScreenHere()
}
}
fun iosLikeSlide(animationSpec: FiniteAnimationSpec<Float> = tween()): StackAnimator =
stackAnimator(animationSpec = animationSpec) { factor, direction, content ->
val newFactor = when (direction) {
Direction.ENTER_FRONT -> factor
Direction.EXIT_FRONT -> factor
Direction.ENTER_BACK -> factor * 0.5f
Direction.EXIT_BACK -> factor * 0.5f
}
content(Modifier.offsetXFactor(factor = newFactor))
}
fun Modifier.slideExitModifier(progress: Float): Modifier {
return offsetXFactor(progress)
}
fun Modifier.slideEnterModifier(progress: Float): Modifier {
return offsetXFactor((progress - 1f) * 0.5f)
}
private fun Modifier.offsetXFactor(factor: Float): Modifier =
layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.placeRelative(x = (placeable.width.toFloat() * factor).toInt(), y = 0)
}
}
Arkadii Ivanov
06/23/2023, 2:50 PMColton Idle
06/24/2023, 4:50 PMArkadii Ivanov
06/24/2023, 4:52 PMPavel Shnyakin
06/24/2023, 4:58 PMColton Idle
06/24/2023, 8:34 PMArkadii Ivanov
06/24/2023, 8:37 PMArkadii Ivanov
06/24/2023, 8:43 PMPavel Shnyakin
06/25/2023, 1:12 PMArkadii Ivanov
08/20/2023, 12:35 PMArkadii Ivanov
08/20/2023, 12:35 PM@OptIn(ExperimentalDecomposeApi::class)
@Composable
fun RootContent(
component: RootComponent,
modifier: Modifier = Modifier,
) {
Children(
stack = component.childStack,
animation = predictiveBackAnimation(
backHandler = component.backHandler,
animation = stackAnimation(iosLikeSlide()),
exitModifier = { progress, _ -> Modifier.slideExitModifier(progress = progress) },
enterModifier = { progress, _ -> Modifier.slideEnterModifier(progress = progress) },
onBack = component::onBackPressed,
),
modifier = modifier,
) {
Surface {
when (val child = it.instance) {
is RootComponent.Child.Main -> MainContent(component = child.component)
is RootComponent.Child.Details -> DetailsContent(component = child.component)
}
}
}
}
fun iosLikeSlide(animationSpec: FiniteAnimationSpec<Float> = tween()): StackAnimator =
stackAnimator(animationSpec = animationSpec) { factor, direction, content ->
content(
Modifier
.then(if (direction.isFront) Modifier else Modifier.fade(factor + 1F))
.offsetXFactor(factor = if (direction.isFront) factor else factor * 0.5F)
)
}
fun Modifier.slideExitModifier(progress: Float): Modifier =
offsetXFactor(progress)
fun Modifier.slideEnterModifier(progress: Float): Modifier =
fade(progress).offsetXFactor((progress - 1f) * 0.5f)
private fun Modifier.fade(factor: Float) =
drawWithContent {
drawContent()
drawRect(color = Color(red = 0F, green = 0F, blue = 0F, alpha = (1F - factor) / 4F))
}
private fun Modifier.offsetXFactor(factor: Float): Modifier =
layout { measurable, constraints ->
val placeable = measurable.measure(constraints)
layout(placeable.width, placeable.height) {
placeable.placeRelative(x = (placeable.width.toFloat() * factor).toInt(), y = 0)
}
}
Arkadii Ivanov
08/20/2023, 8:50 PM