JetPack组合实施“主页按钮”背板上的功能

发布于 2025-01-24 17:12:59 字数 552 浏览 2 评论 0原文

我通过NavController进行导航。对于某些目的地,我清除了BackStack,例如

navController.navigate(nextScreen) { 
    popUpTo(key) { inclusive = true } 
}

系统“ Back”按钮在主屏幕上按下返回。该托盘仍然包含该应用程序,但是当我尝试继续使用该应用程序时,主要活动会破坏并重新创建。当按下“系统返回按钮”并且背面堆栈为空时,如何实现功能之类的功能? (这意味着不破坏活动,但仅隐式调用onpause()它与“系统主”按钮一起使用)

更新

我有一个带有10个屏幕的注册流。在每个屏幕上,我都会清除后排,因为Buisness逻辑。例如,用户通过了注册流屏幕的4/10。如果他按主页按钮,则该应用将转到后台,当用户返回应用程序时,它以相同的第五屏幕状态打开。但是,如果用户按返回按钮,当他返回应用程序时,导航将来自startDestination IE 10屏幕中的1个。我需要像主页按钮一样将应用程序传递给背景。

I have navigation via NavController. For some destinations i clear backstack like

navController.navigate(nextScreen) { 
    popUpTo(key) { inclusive = true } 
}

and when system "back" button is pressed its returns on home screen. The tray is still holds the app, but when i try continue using the app, main activity destroys and recreates. How can i implement functionality like "system home button" when "system back button" is pressed and backstack is empty? (it means not to destroy activity, but only implicitly call onPause() like it works with "system home button")

UPDATE

I have a registration flow with 10 screens. On each screen i clear backstack, because of buisness logic. For example, user passed 4/10 of registration flow screens. If he press home button, the app would go to background, and when user return to the app it opens with the same state of 5th screen. But if the user press back button, when he returns to the app the navigations would be from startDestination i.e 1 of the 10 screen. I need pass the app to the background like home button do.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

迷爱 2025-01-31 17:12:59

解决您的问题是超级容易的,几乎没有不便。您会发现,问题并不是要在背压上清除活动。这里的真正亮点是撰写的机制。简而言之,不会将其伸展 - 当您按下后面按钮并且活动被“暂停”时,Composable s被销毁了,因为它们不再在屏幕上。这就是构建的方式(用于性能),这也很有意义。即使您在应用程序中仍输入登录凭据,然后返回登录屏幕,即使您在应用程序中的另一个屏幕上导航,该状态也将被清除,因为所有这些组合在屏幕外的那一刻都会被销毁。

现在,这就是viewModel s应该有帮助的地方。您可能要保存在composable的身体中的textfield s的状态实际上需要保存在view> viewmodel中,它甚至可以持续存在配置更改,即重新创建活动,但ViewModel一直存在,直到您的应用被杀死为止。因此,只需在ViewModel中创建一个值,例如

MutableStateOf(“”)的var用户名

,然后将其作为textfield的值传递,然后在<<<代码> onValueChange 就像在composable中定义的值一样。

简单,

编辑

实际上是超级的,几乎没有不便 - 您看到compose提供了Backandler专门用于拦截系统后压力的。在那儿,您可以简单地调用意图,从而触发与系统home按下的操作。意图如下:

Intent(Intent.ACTION_MAIN).apply{
 addCategory(Intent.CATEGORY_HOME)
}.let { startActivity(it) }

容易,

Solving your problem is super-easy, barely an inconvenience. You see, the problem is not that the activity is being cleared on back-press. The real highlight here are the mechanics of Compose. Not gonna stretch it out, simply put - when you press the back button and your activity is "paused", the Composables get destroyed because they are no longer on screen. That is just how Compose is built (for performance) and it makes much sense too. Even if you navigate to another screen inside your app while still inputting your login credentials, and then go back to the login screen, the state would have been cleared, since all those Composables are destroyed the moment they go off-screen.

Now, that's where ViewModels are supposed to help. The state of the TextFields that you might be saving within the Composable's body actually needs to be saved inside a ViewModel, which persists even configuration changes, i.e., the activity is recreated but the ViewModel persists until your app is killed. So, just create a value in the ViewModel, like

var userName by mutableStateOf("")

and then pass that as the value of the TextField, then update it in the onValueChange like you would do with the value defined in the Composable.

Easy,

EDIT

Actually super-easy, barely an inconvenience -- You see Compose provides a BackHandler specifically meant to intercept system back presses. Over there, you could simply call an intent, that triggers an action equivalent to the system Home Press. The intent is as follows:

Intent(Intent.ACTION_MAIN).apply{
 addCategory(Intent.CATEGORY_HOME)
}.let { startActivity(it) }

Easy,

同尘 2025-01-31 17:12:59

谢谢@marsk的答案。
最后,我有这样的想法

    val context = LocalContext.current
    val callback = object: OnBackPressedCallback(
        true
    ) {
        override fun handleOnBackPressed() {
            if (navController.previousBackStackEntry == null) {
                Intent(Intent.ACTION_MAIN).apply{
                    addCategory(Intent.CATEGORY_HOME)
                }.let { context.startActivity(it) }
            } else {
                navController.popBackStack()
            }
        }
    }
    context.getActivity()?.let { activity ->
        val dispatcher = activity.onBackPressedDispatcher
        dispatcher.addCallback(activity, callback)
        navController.setLifecycleOwner(activity)
        navController.setOnBackPressedDispatcher(dispatcher)
    }

Thanks @MARSK for answer.
In the end i have somethink like this

    val context = LocalContext.current
    val callback = object: OnBackPressedCallback(
        true
    ) {
        override fun handleOnBackPressed() {
            if (navController.previousBackStackEntry == null) {
                Intent(Intent.ACTION_MAIN).apply{
                    addCategory(Intent.CATEGORY_HOME)
                }.let { context.startActivity(it) }
            } else {
                navController.popBackStack()
            }
        }
    }
    context.getActivity()?.let { activity ->
        val dispatcher = activity.onBackPressedDispatcher
        dispatcher.addCallback(activity, callback)
        navController.setLifecycleOwner(activity)
        navController.setOnBackPressedDispatcher(dispatcher)
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文