简体   繁体   English

Jetpack 撰写导航关闭应用程序而不是返回上一个屏幕

[英]Jetpack compose navigation closes app instead of returning to previous screen

I have implemented the accompanist navigation animation library in my project and have stumbled into two issues.我已经在我的项目中实现了伴奏导航 animation 库,并且偶然发现了两个问题。 The first issue is that the animations aren't being applied when navigating from one screen to another.第一个问题是从一个屏幕导航到另一个屏幕时没有应用动画。 The second issue is that the "back" of the system closes the app to the background instead of returning to the previous screen.第二个问题是系统的“返回”将应用程序关闭到后台而不是返回到上一个屏幕。

Here is the layout of the app starting from the MainActivity.这是从 MainActivity 开始的应用程序布局。

MainActivity.kt MainActivity.kt

@ExperimentalAnimationApi
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    private val preDrawListener = ViewTreeObserver.OnPreDrawListener { false }

    override fun onCreate(savedInstanceState: Bundle?) {
        setTheme(R.style.MyHomeTheme)
        super.onCreate(savedInstanceState)

        WindowCompat.setDecorFitsSystemWindows(window, false)

        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.addOnPreDrawListener(preDrawListener)

        lifecycleScope.launch {
            setContent {
                val systemUiController = rememberSystemUiController()

                SideEffect {
                    systemUiController.setStatusBarColor(
                        color = Color.Transparent,
                        darkIcons = true
                    )
                    systemUiController.setNavigationBarColor(
                        color = Color(0x40000000),
                        darkIcons = false
                    )
                }
                MyHomeApp(
                    currentRoute = Destinations.Welcome.WELCOME_ROUTE
                )
            }
            unblockDrawing()
        }
    }

    private fun unblockDrawing() {
        val content: View = findViewById(android.R.id.content)
        content.viewTreeObserver.removeOnPreDrawListener(preDrawListener)
        content.viewTreeObserver.addOnPreDrawListener { true }
    }
}

MyHomeApp.kt MyHomeApp.kt

@ExperimentalAnimationApi
@Composable
fun MyHomeApp(currentRoute: String) {
    MyHomeTheme {
        ProvideWindowInsets {
            val navController = rememberAnimatedNavController()
            val scaffoldState = rememberScaffoldState()
            val darkTheme = isSystemInDarkTheme()

            val items = listOf(
                HomeTab.Dashboard,
                HomeTab.Details,
                HomeTab.Settings
            )

            val navBackStackEntry by navController.currentBackStackEntryAsState()
            val currentDestination = navBackStackEntry?.destination

            val bottomPaddingModifier = if (currentDestination?.route?.contains("welcome") == true) {
                Modifier
            } else {
                Modifier.navigationBarsPadding()
            }

            Scaffold(
                modifier = Modifier
                    .fillMaxSize()
                    .then(bottomPaddingModifier),
                scaffoldState = scaffoldState,
                bottomBar = {
                    if (currentDestination?.route in items.map { it.route }) {
                        BottomNavigation {
                            items.forEach { screen ->
                                BottomNavigationItem(
                                    label = { Text(screen.title) },
                                    icon = {},
                                    selected = currentDestination?.hierarchy?.any { it.route == screen.route } == true,
                                    onClick = {
                                        navController.navigate(screen.route) {
                                            // Pop up to the start destination of the graph to
                                            // avoid building up a large stack of destinations
                                            // on the back stack as users select items
                                            popUpTo(navController.graph.findStartDestination().id) {
                                                saveState = true
                                            }
                                            // Avoid multiple copies of the same destination when
                                            // reselecting the same item
                                            launchSingleTop = true
                                            // Restore state when reselecting a previously selected item
                                            restoreState = true
                                        }
                                    }
                                )
                            }
                        }
                    }
                }
            ) { innerPadding ->
                MyHomeNavGraph(
                    modifier = Modifier.padding(innerPadding),
                    navController = navController,
                    startDestination = navBackStackEntry?.destination?.route ?: currentRoute
                )
            }
        }
    }
}

sealed class HomeTab(
    val route: String,
    val title: String
) {
    object Dashboard : HomeTab(
        route = Destinations.Home.HOME_DASHBOARD,
        title = "Dashboard"
    )

    object Details : HomeTab(
        route = Destinations.Home.HOME_DETAILS,
        title = "Details"
    )

    object Settings : HomeTab(
        route = Destinations.Home.HOME_SETTINGS,
        title = "Settings"
    )
}

MyHomeNavGraph.kt MyHomeNavGraph.kt

@ExperimentalAnimationApi
@Composable
fun MyHomeNavGraph(
    modifier: Modifier = Modifier,
    navController: NavHostController,
    startDestination: String
) {
     val actions = remember(navController) { Actions(navController = navController) }

    AnimatedNavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable(
            route = Destinations.Welcome.WELCOME_ROUTE,
            enterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            exitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            popEnterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            },
            popExitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_LOGIN_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            }
        ) {
            WelcomeScreen(
                navigateToLogin = actions.navigateToWelcomeLogin,
                navigateToRegister = actions.navigateToWelcomeRegister,
            )
        }
        composable(
            route = Destinations.Welcome.WELCOME_LOGIN_ROUTE,
            enterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            exitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Left, animationSpec = tween(700))
                    else -> null
                }
            },
            popEnterTransition = {
                when (initialState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideIntoContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            },
            popExitTransition = {
                when (targetState.destination.route) {
                    Destinations.Welcome.WELCOME_ROUTE ->
                        slideOutOfContainer(towards = AnimatedContentScope.SlideDirection.Right, animationSpec = tween(700))
                    else -> null
                }
            }
        ) {
            WelcomeLoginScreen(
                // Arguments will be passed to navigate to the home screen or other
            )
        }
    }
}

class Actions(val navController: NavHostController) {
    // Welcome
    val navigateToWelcome = {
        navController.navigate(Destinations.Welcome.WELCOME_ROUTE)
    }
    val navigateToWelcomeLogin = {
        navController.navigate(Destinations.Welcome.WELCOME_LOGIN_ROUTE)
    }
}

For simplicity's sake, you can assume that the screens are juste a box with a button in the middle which executes the navigation when they are clicked.为简单起见,您可以假设屏幕只是一个中间有一个按钮的框,当单击它们时执行导航。

The accompanist version I am using is 0.24.1-alpha (the latest as of this question) and I am using compose version 1.2.0-alpha02 and kotlin 1.6.10.我使用的伴奏版本是 0.24.1-alpha(截至本问题的最新版本),我使用的是 compose 版本 1.2.0-alpha02 和 kotlin 1.6.10。

In terms of animation, the only difference I can see with the accompanist samples is that I don't pass the navController to the screens but I don't see how that could be an issue.就 animation 而言,我可以看到与伴奏样本的唯一区别是我没有将 navController 传递给屏幕,但我不知道这可能是个问题。

And in terms of using the system back which should return to a previous, I'm genuinely stuck in terms of what could cause the navigation to close the app instead of going back.在使用应该返回到以前的系统返回方面,我真的被什么可能导致导航关闭应用程序而不是返回。 On other projects, the system back works just fine but not with this one.在其他项目中,系统返回工作正常,但不适用于这个。 Is the use of the accompanist navigation incompatible?伴奏导航的使用不兼容吗? I'm not sure.我不确定。

Any help is appreciated!任何帮助表示赞赏!

I found the source of the issue.我找到了问题的根源。

The fact that I was setting the startDestination parameter to navBackStackEntry?.destination?.route?: currentRoute meant that each change to the navBackStackEntry recomposed the MyHomeNavGraph and hence the backstack was reset upon the recomposition.我将startDestination参数设置为navBackStackEntry?.destination?.route?: currentRoute的事实意味着对navBackStackEntry的每次更改都会重新组合 MyHomeNavGraph,因此在重新组合时会重置回栈。

Note to self, watch out when copying navigation from multiple sources!提醒自己,从多个来源复制导航时要小心!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Jetpack 导航启动前一屏幕 - Jetpack navigation initiating previous screen Jetpack Compose Navigation 无限加载屏幕 - Jetpack Compose Navigation loads screen infinitely 在使用 Jetpack Compose 的导航组件时,弹出由可组合表示的屏幕(从“返回堆栈”)返回上一个屏幕? - Popping off screen (from “back stack”) represented by a composable to go back to previous screen while using navigation component of Jetpack Compose? Jetpack Compose WebView 处理返回导航和 Go 到上一页 - Jetpack Compose WebView Handling Back Navigation And Go To Previous Page 后退按钮关闭应用程序而不是转到上一个片段 android 导航组件 - Back button closes app instead of going to previous fragment android navigation component 正在保存的应用程序关闭但不返回上一个活动 - On save app closes without returning to previous activity 在 Jetpack Compose 中导航到没有先前脚手架的另一个屏幕 - Navigate to another screen without the previous scaffold in Jetpack Compose 如何防止在jetpack撰写导航中多次创建屏幕 - How to prevent multiple creation of a screen in jetpack compose navigation Jetpack Compose 底部导航、fab 按钮和保存屏幕 state - Jetpack Compose bottom navigation, fab button and save screen state 如何使用 Jetpack Compose 导航将 bitmap 从一个屏幕传递到另一个屏幕 - how to pass bitmap from a screen to another using jetpack compose navigation
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM