首页 > 解决方案 > 如何处理片段和视图分页器之间的回栈?

问题描述

我正在使用有 2 页的 ViewPager。该 ViewPager 的第一页是 MainFragment。MainFragment 具有 ViewPager 作为bottomNavigationView. 每个页面都有一个FragmentContainerView,默认情况下它们分别包含 HomeFragment、CommunityFragment 和 NotificationFragment。

这是源代码,这是项目的APK。因此,您可以轻松地对其进行测试和改进。

现在,如果我在 HomeFragment 中并单击配置文件按钮,则它会处理到 ProfileFragment 并从那里进行设置等等。在点击后退按钮时,它会一一完美地返回。但它不会发生与其他相同FragmentContainerView。即使他们直接返回到父片段。总的来说,我无法处理不同 ViewPager 和片段之间的 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
}

标签: androidandroid-fragmentsandroid-viewpagerback-stackonbackpressed

解决方案


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

supportFragmentManager.popBackStack(null,FragmentManager.POP_BACK_STACK_INCLUSIVE)

如果您阅读标志的描述,POP_BACK_STACK_INCLUSIVE它会说:

如果设置,并且提供了返回堆栈条目的名称或 ID,则将使用所有匹配的条目,直到找到不匹配的条目或到达堆栈底部。否则,将删除该条目之前但不包括该条目的所有条目。

所以它一次删除了多个条目。

它适用于主屏幕的原因是它从未达到过这种情况。它总是出现在第一种情况下:

layoutManager.findFirstCompletelyVisibleItemPosition() == 0 -> {
                        super.onBackPressed()
                    }  

这正是您的案例所需要的,super.onBackPressed()当您想一次只弹出一个片段时只需调用即可。所以你的最终代码变成了这样:

在您的 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:来自评论

我想在底部导航选择更改时清除后台堆栈。

如果您想在更改底部导航选择更改时清除选择,那么您必须设置一个侦听器并清除您的后退堆栈,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
        }  

其余的可以保持不变。试试这个,让我知道。


推荐阅读