[BUG] ModalBottomSheet with nested NavHost breaks the Composition
tomczyn opened this issue · comments
Describe the bug
When nesting a NavHost
inside a ModalBottomSheet
content, it shows visual glitches instead of a correct Composables
. By glitches I mean nested NavHost
(bottom sheet content) is being displayed on the sheet and underneath the sheet, Compose
is copying the content to two places and not displaying the original NavHost
at all.
What it should show, blue is a main view (whole screen home NavHost
), red is bottom sheet content (150.dp
height).
What is shown, bottom sheet content displayed on the sheet and underneath it.
Minimal reproducible example
@Composable
fun App() {
PreComposeApp {
MaterialTheme {
Column(modifier = Modifier.fillMaxSize()) {
var showBottomSheet by remember { mutableStateOf(false) }
val navigator = rememberNavigator()
NavHost(
navigator = navigator,
navTransition = NavTransition(),
initialRoute = "/home",
) {
scene(route = "/home") {
Column(
Modifier.fillMaxSize().background(Color.Blue),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Main Title")
Button(onClick = { showBottomSheet = true }) {
Text("Show bottom sheet")
}
}
}
}
if (showBottomSheet) {
val sheetState = rememberModalBottomSheetState()
val scope = rememberCoroutineScope()
ModalBottomSheet(
sheetState = sheetState,
onDismissRequest = { showBottomSheet = false },
dragHandle = null,
content = {
val sheetNavigator = rememberNavigator()
NavHost( // Sheet NavHost, when removed everything starts to work correctly
navigator = sheetNavigator,
navTransition = NavTransition(),
initialRoute = "/sheet",
) {
scene(route = "/sheet") {
Column(
Modifier.fillMaxWidth().height(150.dp)
.background(Color.Red),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("BottomSheet Title")
Button(
onClick = {
scope.launch { sheetState.hide() }
.invokeOnCompletion {
if (!sheetState.isVisible)
showBottomSheet = false
}
}
) {
Text("Hide bottom sheet")
}
}
}
}
}
)
}
}
}
}
}
Repo: https://github.com/tomczyn/PreCompose-Sample
Branch with StateHolder
fix: https://github.com/tomczyn/PreCompose-Sample/tree/fix
Workaround
It appears that wrapping the NavHost
in StateHolder
solves the problem with displaying the content, but the behavior of the bottom sheet is still a little bit bugged with this workaround. Instead, it sometimes doesn't show the showing/hidding animation of the bottom sheet correctly.
val stateHolder = remember { StateHolder() }
CompositionLocalProvider(LocalStateHolder provides stateHolder) {
NavHost( // Sheet NavHost
...
}
It appears that rememberNavigator
consistently returns the same Navigator
. One possible workaround is to assign a unique name each time rememberNavigator
is used.
Perhaps we should consider automatically assigning different names when using rememberNavigator
Thank you, that works! The most important thing is it can be very easily solved, but good point on the behavior change.