Skip to content

Commit c8ddf88

Browse files
authored
Wrap a screen content to a Box for the iOS back animation blackout (#2146)
It fixes a crash when NavHost is located inside a scrollable container and there is no available max size. The reason is an additional iOS blackout layer. Simple reproducer: ```kotlin Column(Modifier.fillMaxSize().verticalScroll(rememberScrollState())) { NavHost(...) } ``` Inside the `verticalScroll` it is not possible to measure constrains: ```kotlin .layout { m, c -> val placeable = m.measure(Constraints.fixed(c.maxWidth, c.maxHeight) layout(c.minWidth, c.minHeight) { placeable.place(0, 0) } } ``` So, I wrapped the screen content in an additional Box and use `matchParentSize()` modifier now. Fixes https://youtrack.jetbrains.com/issue/CMP-8233 ## Release Notes ### Fixes - Navigation - Fix a crash on iOS when a `NavHost` is located in a scrollable container
1 parent 4b54dc8 commit c8ddf88

File tree

2 files changed

+33
-36
lines changed

2 files changed

+33
-36
lines changed

navigation/navigation-compose/src/commonMain/kotlin/androidx/navigation/compose/NavHost.kt

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import androidx.compose.animation.core.animate
3131
import androidx.compose.animation.core.rememberTransition
3232
import androidx.compose.animation.core.tween
3333
import androidx.compose.animation.togetherWith
34+
import androidx.compose.foundation.layout.Box
35+
import androidx.compose.foundation.layout.BoxScope
3436
import androidx.compose.runtime.Composable
3537
import androidx.compose.runtime.DisposableEffect
3638
import androidx.compose.runtime.LaunchedEffect
@@ -495,7 +497,7 @@ internal fun NavHost(
495497
(@JvmSuppressWildcards
496498
AnimatedContentTransitionScope<NavBackStackEntry>.() -> SizeTransform?)?,
497499
drawOnBottomEntryDuringAnimation:
498-
(@Composable (isBackAnimation: Boolean, progress: Float) -> Unit)?,
500+
(@Composable BoxScope.(isBackAnimation: Boolean, progress: Float) -> Unit)?,
499501
limitBackGestureSwipeEdge: Int?
500502
) {
501503

@@ -719,28 +721,33 @@ internal fun NavHost(
719721
// while in the scope of the composable, we provide the navBackStackEntry as the
720722
// ViewModelStoreOwner and LifecycleOwner
721723
currentEntry?.LocalOwnersProvider(saveableStateHolder) {
722-
(currentEntry.destination as ComposeNavigator.Destination).content(
723-
this,
724-
currentEntry
725-
)
726-
}
724+
val destination = (currentEntry.destination as ComposeNavigator.Destination)
725+
if (drawOnBottomEntryDuringAnimation == null) {
726+
destination.content(this, currentEntry)
727+
} else {
728+
Box {
729+
with(this@AnimatedContent) {
730+
destination.content(this, currentEntry)
731+
}
727732

728-
if (currentEntry != null && drawOnBottomEntryDuringAnimation != null) {
729-
val currentEntryId = currentEntry.id
730-
val initialEntryId = transition.segment.initialState.id
731-
val targetEntryId = transition.segment.targetState.id
732-
if (
733-
zIndices.contains(currentEntryId) &&
734-
zIndices.contains(initialEntryId) &&
735-
zIndices.contains(targetEntryId)
736-
) {
737-
val currentEntryZ = zIndices[currentEntryId]
738-
val initialEntryZ = zIndices[initialEntryId]
739-
val targetEntryZ = zIndices[targetEntryId]
740-
val isDrawBehind = currentEntryZ < initialEntryZ || currentEntryZ < targetEntryZ
741-
if (isDrawBehind) {
742-
val isGoBack = currentEntryZ == targetEntryZ
743-
drawOnBottomEntryDuringAnimation(isGoBack, transitionState.fraction)
733+
val currentEntryId = currentEntry.id
734+
val initialEntryId = transition.segment.initialState.id
735+
val targetEntryId = transition.segment.targetState.id
736+
if (
737+
zIndices.contains(currentEntryId) &&
738+
zIndices.contains(initialEntryId) &&
739+
zIndices.contains(targetEntryId)
740+
) {
741+
val currentEntryZ = zIndices[currentEntryId]
742+
val initialEntryZ = zIndices[initialEntryId]
743+
val targetEntryZ = zIndices[targetEntryId]
744+
val isDrawBehind =
745+
currentEntryZ < initialEntryZ || currentEntryZ < targetEntryZ
746+
if (isDrawBehind) {
747+
val isGoBack = currentEntryZ == targetEntryZ
748+
drawOnBottomEntryDuringAnimation(isGoBack, transitionState.fraction)
749+
}
750+
}
744751
}
745752
}
746753
}

navigation/navigation-compose/src/uikitMain/kotlin/androidx/navigation/compose/NavHost.uikit.kt

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,15 @@ import androidx.compose.animation.EnterTransition
2121
import androidx.compose.animation.ExitTransition
2222
import androidx.compose.animation.SizeTransform
2323
import androidx.compose.foundation.layout.Box
24+
import androidx.compose.foundation.layout.BoxScope
2425
import androidx.compose.runtime.Composable
25-
import androidx.compose.runtime.remember
2626
import androidx.compose.ui.Alignment
2727
import androidx.compose.ui.ExperimentalComposeUiApi
2828
import androidx.compose.ui.Modifier
2929
import androidx.compose.ui.backhandler.BackEventCompat
3030
import androidx.compose.ui.draw.drawBehind
3131
import androidx.compose.ui.graphics.Color
32-
import androidx.compose.ui.layout.layout
3332
import androidx.compose.ui.platform.LocalLayoutDirection
34-
import androidx.compose.ui.unit.Constraints
3533
import androidx.compose.ui.unit.LayoutDirection
3634
import androidx.navigation.NavBackStackEntry
3735
import androidx.navigation.NavGraph
@@ -58,16 +56,11 @@ actual fun NavHost(
5856
sizeTransform == DefaultNavTransitions.sizeTransform
5957

6058
if (isDefaultTransition) {
61-
val iosBlackout = @Composable { isBackAnimation: Boolean, progress: Float ->
59+
val iosBlackout = @Composable fun BoxScope.(isBackAnimation: Boolean, progress: Float) {
6260
val blackoutFraction = if (isBackAnimation) 1 - progress else progress
6361
Box(
6462
modifier = Modifier
65-
.layout { m, c ->
66-
val placeable = m.measure(
67-
Constraints.fixed(c.maxWidth, c.maxHeight)
68-
)
69-
layout(c.minWidth, c.minHeight) { placeable.place(0, 0) }
70-
}
63+
.matchParentSize()
7164
.drawBehind {
7265
drawRect(Color.Black, alpha = 0.106f * blackoutFraction)
7366
}
@@ -106,7 +99,4 @@ actual fun NavHost(
10699
null
107100
)
108101
}
109-
110-
111-
112-
}
102+
}

0 commit comments

Comments
 (0)