accompanist
accompanist copied to clipboard
[Navigation Material] App crashes on rotation when using Scaffold and a "tall" bottom sheet
Description If we have a bottom sheet tall enough (I'm guessing more than half) and we wrap our NavHost in a Scaffold, then when rotating the device while the bottom sheet is the active destination, the app crashes.
Click to expand crash stack trace
2022-04-29 16:37:55.046 30964-30964/com.ramcosta.samples.playground E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.ramcosta.samples.playground, PID: 30964
java.lang.IllegalArgumentException: The initial value must have an associated anchor.
at androidx.compose.material.SwipeableState.ensureInit$material_release(Swipeable.kt:138)
at androidx.compose.material.SwipeableKt$swipeable$3.invoke(Swipeable.kt:594)
at androidx.compose.material.SwipeableKt$swipeable$3.invoke(Swipeable.kt:573)
at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:263)
at androidx.compose.ui.ComposedModifierKt$materialize$result$1.invoke(ComposedModifier.kt:258)
at androidx.compose.ui.Modifier$Element$DefaultImpls.foldIn(Modifier.kt:107)
at androidx.compose.ui.ComposedModifier.foldIn(ComposedModifier.kt:172)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.CombinedModifier.foldIn(Modifier.kt:149)
at androidx.compose.ui.ComposedModifierKt.materialize(ComposedModifier.kt:258)
at androidx.compose.ui.layout.LayoutKt$materializerOf$1.invoke-Deg8D_g(Layout.kt:221)
at androidx.compose.ui.layout.LayoutKt$materializerOf$1.invoke(Layout.kt:220)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.material.SurfaceKt$Surface$6.invoke(Surface.kt:302)
at androidx.compose.material.SurfaceKt$Surface$6.invoke(Surface.kt:255)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:252)
at androidx.compose.material.SurfaceKt.Surface-F-jzlyU(Surface.kt:110)
at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$1.invoke(ModalBottomSheet.kt:262)
at androidx.compose.material.ModalBottomSheetKt$ModalBottomSheetLayout$1.invoke(ModalBottomSheet.kt:247)
at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:116)
at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
at androidx.compose.runtime.internal.ComposableLambdaImpl$invoke$1.invoke(ComposableLambda.jvm.kt:127)
at androidx.compose.runtime.RecomposeScopeImpl.compose(RecomposeScopeImpl.kt:140)
at androidx.compose.runtime.ComposerImpl.recomposeToGroupEnd(Composer.kt:2158)
at androidx.compose.runtime.ComposerImpl.skipCurrentGroup(Composer.kt:2404)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2585)
at androidx.compose.runtime.ComposerImpl$doCompose$2$5.invoke(Composer.kt:2571)
at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:247)
at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
at androidx.compose.runtime.ComposerImpl.doCompose(Composer.kt:2571)
at androidx.compose.runtime.ComposerImpl.recompose$runtime_release(Composer.kt:2547)
at androidx.compose.runtime.CompositionImpl.recompose(Composition.kt:620)
at androidx.compose.runtime.Recomposer.performRecompose(Recomposer.kt:786)
at androidx.compose.runtime.Recomposer.access$performRecompose(Recomposer.kt:105)
at androidx.compose.runtime.Recomposer$runRecomposeAndApplyChanges$2$2.invoke(Recomposer.kt:456)
Steps to reproduce
- Have a Scaffold with a NavHost and a bottom sheet destination.
- The bottom sheet destination should be "tall" (In my device above ~330 dp it would crash)
- Navigate to the bottom sheet destination
- Rotate the device
Once I reproduced it, I tried to find a minimal example and this is what I got (based on the sample in the Project):
Click to expand the sample code
class BottomSheetNavSample : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
PlaygroundTheme { // <-- REPLACE THEME WITH THE PROJECT'S ONE
BottomSheetNavDemo()
}
}
}
}
private object Destinations {
const val Home = "HOME"
const val Feed = "FEED"
const val Sheet = "SHEET"
}
@OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalAnimationApi::class)
@Composable
fun BottomSheetNavDemo() {
val bottomSheetNavigator = rememberBottomSheetNavigator()
val navController = rememberNavController(bottomSheetNavigator)
ModalBottomSheetLayout(bottomSheetNavigator) {
Scaffold { // <-- SEEMS IMPORTANT TO REPRODUCE
NavHost(
navController = navController,
startDestination = Destinations.Home
) {
composable(Destinations.Home) {
HomeScreen(
showSheet = {
navController.navigate(Destinations.Sheet + "?arg=From Home Screen")
},
showFeed = { navController.navigate(Destinations.Feed) }
)
}
composable(Destinations.Feed) { Text("Feed!") }
bottomSheet(Destinations.Sheet + "?arg={arg}") { backstackEntry ->
val arg = backstackEntry.arguments?.getString("arg") ?: "Missing argument :("
BottomSheet(
showFeed = { navController.navigate(Destinations.Feed) },
showAnotherSheet = {
navController.navigate(Destinations.Sheet + "?arg=${UUID.randomUUID()}")
},
arg = arg
)
}
}
}
}
}
@Composable
private fun HomeScreen(showSheet: () -> Unit, showFeed: () -> Unit) {
Column(Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally) {
Text("Body")
Button(onClick = showSheet) {
Text("Show sheet!")
}
Button(onClick = showFeed) {
Text("Navigate to Feed")
}
}
}
@Composable
private fun BottomSheet(showFeed: () -> Unit, showAnotherSheet: () -> Unit, arg: String) {
// Box(
// modifier = Modifier.height(400.dp) // !! ALSO makes it crash, or fillMaxHeight or fillMaxSize
// .background(Color.Yellow)
// ) {
Column {
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Text("Sheet with arg: $arg")
Button(onClick = showFeed) {
Text("Click me to navigate!")
}
Button(onClick = showAnotherSheet) {
Text("Click me to show another sheet!")
}
}
// }
}
Expected behavior When orientation changes, the app shouldn't crash. I'm guessing it should default to the half expanded state.
Additional context This was discovered while investigating an issue on Compose Destinations library.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
This issue is relevant and it's still happening to me even on the latest release. So I don't think it should be closed
If anyone else is facing this issue, I've made a quick (and bad) workaround this, you can check it out in this gist Basically I just made copies of some components and now when the screen is rotated the old bottom sheet state doesn't get restored, which is fine for me since at least it's not crashing anymore
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.
I'm seeing the same crash in 0.25.1. Only when rotating from landscape to portrait
We're aware of this issue, it needs to be fixed upstream. Star for updates: https://issuetracker.google.com/issues/182882364
v0.29.0-alpha addresses this issue. Please let us know if you can still reproduce it with this version.
Here's a possible implementation on the app side to avoid the crash (using 1.4.0-alpha04) https://gist.github.com/angiesasmita/a85c10b51f6bf0931a0be8dc5052e736
Discussed offline, this issue is fixed in v0.29.0-alpha. A similar issue (with a different stacktracke) in v0.29.0-alpha: #1482
It has been fixed upstream and will be fixed with the next Compose release.