无论如何交换或重新排序片段 BackStack 条目?

Is there anyway to swap or reorder fragment BackStack entry?

正在创建多个片段应用程序,这需要轻松更改片段选项卡,必须保留其 BackStack 条目。用户点击片段必须立即弹出。我认为重新排序 BackStack 是最好的选择。有人知道如何重新排序 BackStack 吗?

我有 5 个片段 A、B、C、D、E。如果用户打开像 A ---> B ---> C ---> D ---> E 这样的片段。使用默认的后退堆栈,后退键可以正常工作。但是当用户打开 A ---> B ---> C ---> D ---> E ---> B 之后,如果用户点击返回,默认返回堆栈将转到 A.

这个用例没有 api,但有其他方法可以这样做:

例子

FragmentBackStackModifyActivity

用户沿着路径 A ---> B ---> C ---> D ---> E 然后他想来到 B。所以你应该做的是:

  • 检查 B 是否已经在返回堆栈中。
  • 如果存在,则popBackStackImmediate到return到B
  • 如果没有,则正常添加片段B

所以替换片段应该是这样的:

public void replaceFragment(Fragment fragment) {
    String fragmentTag =  fragment.getClass().getCanonicalName(); //unique name for the fragment, which will be used as tag.

    FragmentManager fragmentManager = getSupportFragmentManager();
    boolean isPopped = fragmentManager.popBackStackImmediate(fragmentTag, 0); // trying to return to the previous state of B if it exists.

    if (!isPopped && fragmentManager.findFragmentByTag(fragmentTag) == null){ // fragment is not in the backstack, so create it.
        FragmentTransaction ft = fragmentManager.beginTransaction();
        ft.replace(R.id.frame_layout, fragment, fragmentTag);
        ft.addToBackStack(fragmentTag);
        ft.commit();
    }
}

记住,这将 return 到 B 以前的状态

提示:由于您不想要任何片段的两个实例,因此请尝试为它们创建一个单例实例。因为,如果您正在创建片段的新实例并且该片段已经存在于返回堆栈中,那么新实例将被忽略(因为您正在 return 返回到以前的状态)。

你可以试试这个...

onBackpressed

 @Override
public void onBackPressed() {


  Fragment f = getSupportFragmentManager().findFragmentById(R.id.frame_container);
  if (f instanceof FragmentE)
{
     FragmentManager fragmentManager = getFragmentManager();
fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-1).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);


} else if (f instanceof FragmentD) {

 FragmentManager fragmentManager = getFragmentManager();
   fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-2).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);

}

else if (f instanceof FragmentC) {

 FragmentManager fragmentManager = getFragmentManager();
   fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-3).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);

}

else if (f instanceof FragmentB) {

 FragmentManager fragmentManager = getFragmentManager();
   fragmentManager.popBackStack(fragmentManager.getBackStackEntryAt(fragmentManager.getBackStackEntryCount()-4).getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);

}
   else
{
        super.onBackPressed();

 }
}

for back remove stack

 final android.app.FragmentManager fm = getFragmentManager();

    fm.addOnBackStackChangedListener(new android.app.FragmentManager.OnBackStackChangedListener() {
        @Override
        public void onBackStackChanged() {

            if (getSupportFragmentManager().getBackStackEntryCount() ==0) {
               // dLayout.closeDrawers();
                finish();
            }
            else
            {
               // dLayout.closeDrawers();

            }
        }
    });

只有在之前没有添加片段时才可以调用addToBackstack()

假设在您的情况下,当用户在片段 E 中并且当用户调用片段 B 时检查片段 B 是否已添加到返回堆栈中

如果是,则不要为该 FragmentTransaction 调用 addToBackstack。

否则,调用 addToBackstack()

检查我的示例代码:

 private void addFragment (Fragment fragment){
        boolean isFragment=false;
        String backStateName = fragment.getClass().getName();
        FragmentManager fm = getFragmentManager();

        for(int entry = 0; entry < fm.getBackStackEntryCount(); entry++){
            Log.i(TAG, "Found fragment: " + fm.getBackStackEntryAt(entry).getId());
            if(fm.getBackStackEntryAt(entry).getId().equalsIgnoreCase(FragmentB))// check if fragment is in back stack
            {
                isFragment=true;
            }
        }

        if (!isFragment){ //fragment added to back stack, create it.
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragmentContainer, FragmentB).addToBackStack(FragmentB).commit();
        }else {//else dont call addToBackStack()
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragmentContainer, FragmentB).commit();
        }
    }

只需将此代码放入您的 MainActivity

   @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            //super.onBackPressed();

            if (getFragmentManager().getBackStackEntryCount() == 1) {
                finish();
            }
            getFragmentManager().popBackStack();
        }
    }

这里getFragmentManager().getBackStackEntryCount() == 0会检查堆栈入口是否为0,如果为0则Activity结束。

在你的情况下 A --> B --> C --> D --> E --> B

A 将在 0,
B 将在 1,
C 上 2,
D 上 3,
E 上 4,
B 上 5

因此,当您单击返回时,if 条件将检查返回堆栈计数是否为 0。

使用不可滑动的 viewpager 并在 addOnPageChangeListener 上创建数组列表并保存所有打开的页面。 onBackPressed 将比较数组列表并显示页面。