android - 如何处理 fragment 和viewpager之间的回栈?

标签 android android-fragments android-viewpager back-stack onbackpressed

我正在使用有 2 页的 ViewPager。该 ViewPager 的第一页是 MainFragment。 MainFragment 的 ViewPager 为 bottomNavigationView .每页都有一个FragmentContainerView默认情况下,它们分别包含 HomeFragment、CommunityFragment 和 NotificationFragment。
这是Source Code这是APK的项目。因此,您可以轻松地对其进行测试和改进。
现在,如果我在 HomeFragment 中并单击配置文件按钮,则它会处理到 ProfileFragment 并从那里进行设置等等。在点击后退按钮时,它会一一完美地返回。但它不会发生与其他 FragmentContainerView 相同的情况.即使他们直接返回到父 fragment 。总的来说,我无法处理不同 ViewPager 和 fragment 之间的 backstack。
为避免混淆 FragmentContainers我这样交易

val containerId = (view?.parent as ViewGroup).id
activity?.supportFragmentManager?.beginTransaction()?.add(containerId, profileFragment)?.addToBackStack(null)?.commit()
现在MainActivity中BackPressed()的处理就到这里了
if (view_pager_main_activity?.currentItem == 0)
{
    if (view_pager_main_fragment?.currentItem == 0)
    {
        val recyclerView = findViewById<RecyclerView>(R.id.recycler_view_home)
        val appbarHome = findViewById<AppBarLayout>(R.id.appbar_home)
        val layoutManager = recyclerView?.layoutManager as LinearLayoutManager
        when {
            layoutManager.findFirstCompletelyVisibleItemPosition() == 0 -> {
                super.onBackPressed()
            }
            supportFragmentManager.backStackEntryCount != 0 -> {
                supportFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
            }
            else -> {
                layoutManager.scrollToPositionWithOffset(0, 0)
                appbarHome.setExpanded(true)
                //recyclerView.smoothScrollToPosition(0)
            }
        }
    }
    else
    {
        // Otherwise, select the previous step.
        view_pager_main_fragment?.setCurrentItem(view_pager_main_fragment.currentItem - 1, false)
    }
}
else
{
    // Otherwise, select the previous step.
    view_pager_main_activity?.currentItem = view_pager_main_activity.currentItem - 1
}

最佳答案

我检查了你的代码,问题是使用

supportFragmentManager.popBackStack(null,FragmentManager.POP_BACK_STACK_INCLUSIVE)
如果您阅读了标志的描述 POP_BACK_STACK_INCLUSIVE它说:

If set, and the name or ID of a back stack entry has been supplied, then all matching entries will be consumed until one that doesn't match is found or the bottom of the stack is reached. Otherwise, all entries up to but not including that entry will be removed.


所以它一次删除了多个条目。
它适用于主屏幕的原因是它从未达到过这种情况。它总是出现在第一种情况下:
layoutManager.findFirstCompletelyVisibleItemPosition() == 0 -> {
                        super.onBackPressed()
                    }  
这正是您的案例所需要的,只需调用 super.onBackPressed()当您想一次只弹出一个 fragment 时。所以你的最终代码变成了这样:
在你的 MainActivity 的 onBackPressed()
override fun onBackPressed() {
        if (view_pager_main_activity?.currentItem == 0) {
            if (view_pager_main_fragment?.currentItem == 0) {
                val recyclerView = findViewById<RecyclerView>(R.id.listRecyclerView)
                val appbarHome = findViewById<AppBarLayout>(R.id.appbar_home)
                val layoutManager = recyclerView?.layoutManager as LinearLayoutManager
                when {
                    layoutManager.findFirstCompletelyVisibleItemPosition() == 0 -> {
                        super.onBackPressed()
                    }
                    //This is never reached. It can be removed
                    supportFragmentManager.backStackEntryCount != 0 -> {
                        supportFragmentManager.popBackStack(
                            null,
                            FragmentManager.POP_BACK_STACK_INCLUSIVE
                        )
                    }
                    else -> {
                        layoutManager.scrollToPositionWithOffset(0, 0)
                        appbarHome.setExpanded(true)
                        //recyclerView.smoothScrollToPosition(0)
                    }
                }
            } else if (supportFragmentManager.backStackEntryCount != 0) {
                super.onBackPressed()
            } else {
                // Otherwise, select the previous step.
                view_pager_main_fragment?.setCurrentItem(
                    view_pager_main_fragment.currentItem - 1,
                    false
                )
            }
        } else if (supportFragmentManager.backStackEntryCount != 0) {
            super.onBackPressed()
        } else {
            // Otherwise, select the previous step.
            view_pager_main_activity?.currentItem = view_pager_main_activity.currentItem - 1
        }
    } 
编辑 1:来自评论

I want to clear the backstack when bottom nav selection changes.


如果您想在更改底部导航选择更改时清除选择,那么您必须设置一个监听器并清除 MainFragment 中的返回堆栈。如下:
view?.bottomNavView?.setOnNavigationItemSelectedListener { item ->
            //check if item is being re-selected then just return and don't do anything
            if (bottomNavView.selectedItemId == item.itemId){
                return@setOnNavigationItemSelectedListener false
            }
            //if the bottom nav item selection changes then clear the back stack of previous tab
            parentFragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)

            when (item.itemId) {
                R.id.homeFragment -> viewPager2.setCurrentItem(0, false)
                R.id.searchFragment -> viewPager2.setCurrentItem(1, false)
                R.id.notificationsFragment -> viewPager2.setCurrentItem(2, false)
            }
            true
        }  
其余的可以保持不变。试试这个,让我知道。

关于android - 如何处理 fragment 和viewpager之间的回栈?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66921543/

相关文章:

android - 如何强制flutter `camera`插件以纵向模式拍照?

android - TabLayout 选项卡选择

Android Viewpager 性能

android - SQLDroid 和加密数据库

android - 解析 android-21 的数据失败不受支持的 major.minor 版本 51.0

java - 全局 EditText 变量

android - 当 fragment 位于另一个 fragment 之上时焦点丢失

android - TabLayout 中的 fragment 仅在用户滑动 Android 时加载

android - 对话 fragment 嵌入取决于设备

android - Espresso : click first item in ListView inside a ViewPager