[BUG] ModalBottomSheet with nested NavHost breaks the Composition
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.