'Use Dialog as navigation destination with jetpack compose

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.



Solution 1:[1]

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()
        }
    }
}

Solution 2:[2]

It's a feature request: https://issuetracker.google.com/issues/179608120 You can star it so perhaps we'll increase it's priority

Solution 3:[3]

Example:

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
                            )
                        }
                    }
                }
            }
        }
    }
}

Result:

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 nwagu
Solution 2 Damir Mihaljinec
Solution 3 Mike