Use Dialog as navigation destination with jetpack compose
Asked Answered
M

5

15

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.

Mako answered 5/5, 2021 at 7:36 Comment(0)
M
29

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()
        }
    }
}
Meyers answered 2/7, 2021 at 22:41 Comment(3)
what about bottom sheet dialogueNachison
How do you dismiss that dialog inside DetailDialogContent() blockCatlin
To dismiss that dialog you can use navController.popBackStack()Ickes
I
3

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
                            )
                        }
                    }
                }
            }
        }
    }
}
Ickes answered 8/5, 2022 at 14:42 Comment(0)
H
1

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

Hancock answered 23/5, 2021 at 8:26 Comment(0)
J
0

According to the Android official documentation from May 2023 there are 2 different use cases for displaying dialogs:

  1. Use Compose navigation dialog() if dialog represents a separate screen in your app that needs its own lifecycle and saved state, independent of any other destination in your navigation graph

  2. For use cases such as AlertDialog, you should use Dialog() composable directly in the composable destination that wants to show that dialog.

Jerboa answered 22/5, 2023 at 20:12 Comment(0)
A
0

You can use dialog in navigation like below

fun NavGraphBuilder.mainNavGraph(navController: NavHostController) {
    navigation(
        startDestination = AppScreen.Main.Home.route,
        route = AppScreen.Main.route
    ) {
        composable(route = AppScreen.Main.Home.route) {

            HomeScreen()
        }

        dialog(route = AppScreen.Main.ProductDetail.route) {  
   
            ProductDetail()
        }
    }
}

If you want to make it full-screen,

    <style name="Theme.DialogFullScreen" parent="@style/ThemeOverlay.MaterialComponents.Dialog">
        <item name="android:windowMinWidthMajor">100%</item>
        <item name="android:windowMinWidthMinor">100%</item>
        <item name="android:backgroundDimEnabled">false</item>
        <item name="android:windowBackground">@color/white</item>
        <item name="android:windowSoftInputMode">adjustResize</item>
        <item name="android:statusBarColor">@color/white</item>
        <item name="android:windowLightStatusBar">true</item>
        <item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
    </style>

    <!-- Main application Light Theme. -->
   <style name="Theme.FireflyCompose" parent="android:Theme.Material.Light.NoActionBar">
        <item name="android:statusBarColor">@color/white</item>
        <item name="android:windowLightStatusBar">true</item>
        <item name="android:dialogTheme">@style/Theme.DialogFullScreen</item>
    </style>
Atwood answered 31/1, 2024 at 18:46 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.