以编程方式返回到后堆栈中的上一个片段


218

假设我有一个活动,其中包含以编程方式添加的片段:

private void animateToFragment(Fragment newFragment, String tag) {
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.fragment_container, newFragment, tag);
    ft.addToBackStack(null);
    ft.commit();
}

返回到可见的先前片段的最佳方法是什么?

我发现在Android中单击按钮时具有触发器后退按钮功能,但我认为模拟后退键事件不是正确的解决方法(而且我也无法使其正常工作):

dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));

调用finish()只会关闭我不感兴趣的活动。

有更好的方法来解决这个问题吗?

Answers:


354

查看getFragmentManager().popBackStack()方法(有多种选择)

http://developer.android.com/reference/android/app/FragmentManager.html#popBackStack()


91
getFragmentManager().popBackStackImmediate();做到了。谢谢。
Aske B.

1
但是我将在哪里放置这种方法?在我的标签听众中?
rasen58

1
没有看到代码,这很难说...但是当您要“关闭”当前片段并返回上一个片段时,它应该进入执行的代码部分。
2012年

1
关于getSupportFragmentManager()
ViliusK

5
不要忘记在代码中添加“ addToBackStack(“ tag”)“。“” fragmentManager.beginTransaction()。replace(R.id.content_frame,fragment).addToBackStack(“ tag”)。commit();“ 如果编写addToBackStack(null),它将自行处理,但是如果提供标记,则应手动处理。
哈立德·赛义夫

129

为了详细说明提供的其他答案,这是我的解决方案(放在“活动”中):

@Override
public void onBackPressed(){
    FragmentManager fm = getFragmentManager();
    if (fm.getBackStackEntryCount() > 0) {
        Log.i("MainActivity", "popping backstack");
        fm.popBackStack();
    } else {
        Log.i("MainActivity", "nothing on backstack, calling super");
        super.onBackPressed();  
    }
}

5
以及为什么会这样。在片段示例developer.android.com/training/basics/fragments/index.html中,它们不覆盖onbackpressed事件,但它们仍可以对片段进行堆栈。我已经使用trasaction.addToBackStack(null); 但什么也没发生。你能解释为什么吗?
2013年

@MurtazaHussain,如果您需要帮助,可能应该问一个新问题。不查看更多代码就很难知道发生了什么。
Kyle Falconer 2013年

2
在我的情况下,我必须要做的fm.getBackStackEntryCount() > 1是在堆栈中只有第一个片段时回调活动。
Facundo Olano 2015年

3
Android已经为您完成此操作:“当后向堆栈上有FragmentTransaction对象,并且用户按下“后退”按钮时,FragmentManager会从后向堆栈中弹出最新的事务,并执行相反的操作(例如,删除该事务中的片段添加了)。” (消息来源)
artkoenig

29

当我们更新/添加片段时,

应该包括.addToBackStack()

getSupportFragmentManager().beginTransaction()
    .add(detailFragment, "detail") // Add this transaction to the back stack (name is an optional name for this back stack state, or null).
    .addToBackStack(null)
    .commit();

在那之后,如果我们getFragments.popBackStackImmediate()添加/更新片段,并返回到当前屏幕,则将返回true。


7

将这些行添加到onBackPressed()方法。如果在back stack上有任何片段,popBackStackImmediate()方法将使您回到上一个片段。

if(getFragmentManager().getBackStackEntryCount() > 0){
     getFragmentManager().popBackStackImmediate();
}
else{
    super.onBackPressed();
}

`


5

当您要在主片段中按回时要关闭应用程序时,此解决方案非常适合基于底部栏的片段导航。

另一方面,当您打开在我的代码中定义为“ DetailedPizza”的辅助片段(片段中的片段)时,它将返回主片段的先前状态。干杯!

背面的内部活动按如下:

Fragment home = getSupportFragmentManager().findFragmentByTag("DetailedPizza");

if (home instanceof FragmentDetailedPizza && home.isVisible()) {
    if (getFragmentManager().getBackStackEntryCount() != 0) {
        getFragmentManager().popBackStack();
    } else {
        super.onBackPressed();
    }
} else {
    //Primary fragment
    moveTaskToBack(true);
}

然后启动另一个片段,如下所示:

Fragment someFragment = new FragmentDetailedPizza();
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.container_body, someFragment, "DetailedPizza");
transaction.addToBackStack("DetailedPizza");
transaction.commit();

3

如果我没有将addToBackStack()添加到片段事务中,那么这些答案将不起作用,但是,您可以使用:

getActivity().onBackPressed();

从您的任何片段回到上一步;


1

使用以下代码以编程方式返回上一个片段。

if ( getFragmentManager().getBackStackEntryCount() > 0) 
{
          getFragmentManager().popBackStack();
          return;
}
super.onBackPressed();

1

要使该片段再次出现,只需将该片段添加到您要向后压入的backstack中,例如:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Fragment fragment = new LoginFragment();
        //replacing the fragment
        if (fragment != null) {
            FragmentTransaction ft = ((FragmentActivity)getContext()).getSupportFragmentManager().beginTransaction();
            ft.replace(R.id.content_frame, fragment);
            ft.addToBackStack("SignupFragment");
            ft.commit();
        }
    }
});

在上述情况下,LoginFragment当我Button button按下时,我正在打开SignupFragment。因此,如果addToBackStack(TAG)在哪里调用,TAG = "SignupFragment"则在按下后退按钮时LoginFragment,我们返回SignUpFragment

编码愉快!


我认为,TAG不会影响,甚至可能为空。
CoolMind

1

通过添加fragment_tran.addToBackStack(null)最后一个片段,我可以返回最后一个片段。

添加新片段

view.findViewById(R.id.changepass).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
            transaction.replace(R.id.container, new ChangePassword());
            transaction.addToBackStack(null);
            transaction.commit();
        }
    });

1

我来这里的目的或想法相同,与此同时,我想到了一个自己的想法,我认为这还不错,并且可以与ViewPager一起使用。

因此,我要做的是在保存viewPager的父活动中重写onBackPressed方法,并将其设置为始终返回负1位置,直到到达第一个片段,然后关闭该活动。

@Override
public void onBackPressed() {
    if(viewPager.getCurrentItem()>0){
        viewPager.setCurrentItem(viewPager.getCurrentItem()-1);
    } else {
        super.onBackPressed();
        this.close();
    }
}

private void close(){
    this.finish();
}

这可能会导致崩溃,就像每次都只向左退回一样,因此如果有标签页并且您跳过片段切换位置(从0到2,然后再按回车键,则会使您进入1,而不是0)

对于我来说,在viewPager中有2个没有选项卡的片段,它做得很好。


类似的问题已经回答。 stackoverflow.com/questions/10863572/...
AtifSayings

0

试试下面的代码:

@Override
    public void onBackPressed() {
        Fragment myFragment = getSupportFragmentManager().findFragmentById(R.id.container);
        if (myFragment != null && myFragment instanceof StepOneFragment) {
            finish();
        } else {
            if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
                getSupportFragmentManager().popBackStack();
            } else {
                super.onBackPressed();
            }
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.