Use Dialog as navigation destination with jetpack compose

Viewed 3015

A dialog can have a rather complex ui, acting more like a floating screen rather than a typical AlertDialog. Therefore it can be desired to let the dialog have its own ViewModel and being able to navigate to it. When using the jetpack compose navigation artifact the code indicates that only one composable is shown at any time inside the NavHost.

Is there a way to navigate to a dialog that is overlaid onto the current ui? This would be in line with how we can navigate to fragment dialogs. Thanks.

3 Answers

Aha. This is now a feature in compose navigation version 2.4.0-alpha04

From the release notes

The NavHost of the navigation-compose artifact now supports dialog destinations in addition to composable destinations. These dialog destinations will each be shown within a Composable Dialog, floating above the current composable destination.

val navController = rememberNavController()
Scaffold { innerPadding ->
    NavHost(navController, "home", Modifier.padding(innerPadding)) {
        composable("home") {
            // This content fills the area provided to the NavHost
            HomeScreen()
        }
        dialog("detail_dialog") {
            // This content will be automatically added to a Dialog() composable
            // and appear above the HomeScreen or other composable destinations
            DetailDialogContent()
        }
    }
}

Example:

enter image description here

val navController = rememberNavController()
NavHost(
    navController = navController,
    startDestination = Screen.Menu.route
) {
    // some other screens here: composable(...) { ... }
    dialog(
        route = "exit_dialog",
        dialogProperties = DialogProperties(
            dismissOnBackPress = true,
            dismissOnClickOutside = true,
        )
    ) {
        Box(modifier = Modifier.width(280.dp)) {
            Box(
                modifier = Modifier
                    .fillMaxWidth()
                    .clip(RoundedCornerShape(10.dp))
                    .background(DialogBorder)
                    .padding(bottom = 3.dp)
                    .clip(RoundedCornerShape(10.dp))
                    .background(DialogBackground),
            ) {
                Column {
                    Column(
                        modifier = Modifier.padding(16.dp),
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        Text(
                            text = stringResource(id = R.string.text_dialog_exit_title),
                            fontSize = 16.sp,
                            fontWeight = FontWeight.Bold,
                            textAlign = TextAlign.Center,
                            color = Color.Black
                        )
                        Text(
                            text = stringResource(id = R.string.text_dialog_exit_description),
                            fontSize = 16.sp,
                            fontWeight = FontWeight.Normal,
                            textAlign = TextAlign.Center,
                            color = Color.Black
                        )
                    }
                    Divider(color = DialogBorder)
                    Row(modifier = Modifier.height(IntrinsicSize.Min)) {
                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .clickable {
                                    // dismiss dialog
                                    navController.popBackStack()
                                }
                                .padding(horizontal = 16.dp, vertical = 8.dp),
                            contentAlignment = Alignment.Center
                        ) {
                            Text(
                                text = stringResource(id = R.string.button_cancel),
                                fontSize = 16.sp,
                                fontWeight = FontWeight.Bold,
                                color = Color.Black
                            )
                        }
                        Box(
                            modifier = Modifier
                                .fillMaxHeight()
                                .width(1.dp)
                                .background(DialogBorder),
                        )
                        Box(
                            modifier = Modifier
                                .weight(1f)
                                .clickable {
                                    // go back to home other screen
                                    navController.popBackStack(
                                        route = "home_screen",
                                        inclusive = false
                                    )
                                }
                                .padding(horizontal = 16.dp, vertical = 8.dp),
                            contentAlignment = Alignment.Center
                        ) {
                            Text(
                                text = stringResource(id = R.string.button_ok),
                                fontSize = 16.sp,
                                fontWeight = FontWeight.Normal,
                                color = Color.Black
                            )
                        }
                    }
                }
            }
        }
    }
}
Related