Skip to content

[Navigation] sheet destination not popped when rapidly dismissing sheet  #1031

@ind1go

Description

@ind1go

Description

I have a layout where a FAB triggers the bottom sheet, and then disappears so as not to cover it. When the sheet is dismissed, the button reappears (see the video under 'expected behaviour').

This works most of the time, however if the sheet is dismissed at a particular moment shortly after it's started, it seems that the the currentBackStackEntryAsState state isn't updated back to the prior destination, and therefore the action to show the button isn't run. There appears to be a race condition.

Video of the failing case:

broken.mp4

Steps to reproduce

  1. Press the button to switch to the sheet and hide the button.
  2. Press the scrim, just about at the time when the sheet animation stops.
  3. Observe that sheet is dismissed, but the button has not reappeared.

Also, in terms of a bit of troubleshooting...

  1. If I add a println as follows:
    val navBackStackEntry by navController.currentBackStackEntryAsState() // existing line
    println("Route: ${navBackStackEntry?.destination?.route}") // new println
    within my MainLayout, then in the erroneous case it ends on SHEET. The HOME navigation does not appear to be triggered.

Full code below.

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
import com.google.accompanist.navigation.material.*

class TestActivity2 : ComponentActivity() {

    @OptIn(ExperimentalMaterialNavigationApi::class, ExperimentalMaterial3Api::class)
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            val bottomSheetNavigator = rememberBottomSheetNavigator()
            val navController = rememberNavController(bottomSheetNavigator)
            var fabVisible by remember { mutableStateOf(true) }

            Scaffold(
                floatingActionButton = {
                    if (fabVisible) {
                        FloatingActionButton(onClick = {
                            navController.navigate(Destinations.SHEET.name)
                        }) {
                            Icon(
                                painter = rememberVectorPainter(image = Icons.Default.Star),
                                contentDescription = null
                            )
                        }
                    }
                },
            ) {
                MainLayout(
                    bottomSheetNavigator = bottomSheetNavigator,
                    navController = navController,
                    onShowSheet = { fabVisible = false },
                    onHideSheet = { fabVisible = true },
                )
            }
        }
    }

    @OptIn(ExperimentalMaterialNavigationApi::class)
    @Composable
    fun MainLayout(
        bottomSheetNavigator: BottomSheetNavigator,
        navController: NavHostController,
        onShowSheet: () -> Unit = {},
        onHideSheet: () -> Unit = {}
    ) {
        val navBackStackEntry by navController.currentBackStackEntryAsState()
        if (navBackStackEntry?.destination?.route == Destinations.SHEET.name) {
            onShowSheet()
        } else {
            onHideSheet()
        }
        ModalBottomSheetLayout(bottomSheetNavigator) {
            NavHost(navController, Destinations.HOME.name) {
                composable(route = Destinations.HOME.name) {
                    Text("This is the home.", fontSize = 16.sp)
                }
                bottomSheet(route = Destinations.SHEET.name) {
                    Text("This is the bottom sheet.", fontSize = 16.sp)
                }
            }
        }
    }

    private enum class Destinations {
        HOME, SHEET
    }
}

Expected behavior

The logic to re-enable the button is triggered, regardless of how quickly I dismiss the sheet.

ok.mp4

Additional context

Compose version 1.2.0-alpha03
Accompanist version 0.24.2-alpha
Android S (Pixel 3a) and Android S (Nexus 5 emulator)

Metadata

Metadata

Assignees

Labels

staleStale issues which are marked for closure

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions