以编程方式返回到 backstack 中的上一个片段

Posted

技术标签:

【中文标题】以编程方式返回到 backstack 中的上一个片段【英文标题】:Programmatically go back to the previous fragment in the backstack 【发布时间】:2012-06-07 11:30:25 【问题描述】:

假设我有一个以编程方式添加片段的活动:

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

返回上一个可见片段的最佳方法是什么?

我找到了Trigger back-button functionality on button click in android,但我认为模拟后键事件不是正确的方法(我也无法让它工作):

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

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

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

【问题讨论】:

【参考方案1】:

看看getFragmentManager().popBackStack()的方法(有几种可供选择)

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

【讨论】:

getFragmentManager().popBackStackImmediate(); 成功了。谢谢。 我会把这个方法放在哪里呢?在我的标签监听器中? 没有看到代码,很难说……但是它应该进入当你想要“关闭”当前片段并返回到前一个片段时执行的代码部分。 getSupportFragmentManager() 怎么样 不要忘记在您的代码中添加“addToBackStack("tag")”。 "fragmentManager.beginTransaction().replace(R.id.content_frame,fragment).addToBackStack("tag").commit();"如果你写 addToBackStack(null) ,它会自己处理它,但如果你给一个标签,你应该手动处理它。【参考方案2】:

要详细说明提供的其他答案,这是我的解决方案(放置在 Activity 中):

@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();  
    

【讨论】:

为什么会这样。在片段示例developer.android.com/training/basics/fragments/index.html 中,它们没有覆盖 onbackpressed 事件,但它们能够回栈片段。我用过 trasaction.addToBackStack(null);但什么也没发生。你能解释一下为什么吗? @MurtazaHussain 如果您需要这方面的帮助,您可能应该问一个新问题。如果不查看更多代码,很难了解发生了什么。 在我的情况下,当堆栈中只有第一个片段时,我必须执行 fm.getBackStackEntryCount() > 1 才能回调活动。 Android 已经为您做到了:"当后台堆栈上有 FragmentTransaction 对象并且用户按下返回按钮时,FragmentManager 会从后台堆栈中弹出最近的事务并执行反向操作(例如,如果事务添加了片段,则将其删除)。” (Source)【参考方案3】:

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

应该包括.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,并返回当前屏幕。

【讨论】:

【参考方案4】:

Android 导航架构组件。

以下代码适用于我:

findNavController().popBackStack()

【讨论】:

当您使用自定义设计的工具栏时,此方法会派上用场。像魅力一样工作。 如果您使用的是 navController,我认为您必须使用此方法 - 我首先尝试了片段管理器(上面的答案),后来尝试使用 navController 导航时出现崩溃。【参考方案5】:

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

getActivity().onBackPressed();

从你的任何片段往回退一步;

【讨论】:

requireActivity().onBackPressed() 对于 Kotlin【参考方案6】:

将这些行添加到您的 onBackPressed() 方法中。如果您在后堆栈上有任何片段,popBackStackImmediate() 方法将使您回到上一个片段 `

if(getFragmentManager().getBackStackEntryCount() > 0)
     getFragmentManager().popBackStackImmediate();

else
    super.onBackPressed();

`

【讨论】:

【参考方案7】:

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

另一方面,当您打开在我的代码中定义为“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();

【讨论】:

【参考方案8】:

Kotlin 答案

    首先,调用片段管理器。 之后,使用 onBackPressed() 方法。

使用 Kotlin 在 Android Studio 4.0 中编码:

fragmentManager?.popBackStack()

【讨论】:

【参考方案9】:

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

if ( getFragmentManager().getBackStackEntryCount() > 0) 

          getFragmentManager().popBackStack();
          return;

super.onBackPressed();

【讨论】:

【参考方案10】:

要使该片段再次出现,只需将该片段添加到您想要返回的 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();
        
    
);

在上述情况下,我在按下Button button 时打开LoginFragment,此时用户在SignupFragment。因此,如果addToBackStack(TAG) 被调用,其中TAG = "SignupFragment",那么当在LoginFragment 中按下后退按钮时,我们会回到SignUpFragment

编码愉快!

【讨论】:

我认为,TAG 不影响,甚至可能为 null。【参考方案11】:

通过在最后一个片段上添加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();
        
    );

【讨论】:

【参考方案12】:

我来到这里寻找或相同的想法,同时我想出了自己的,我相信这不是那么糟糕,如果与 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 个片段,没有标签,它可以很好地完成工作。

【讨论】:

类似问题已得到解答。 ***.com/questions/10863572/…【参考方案13】:

以下 Kotlin 代码对我有用

1.在使用多个片段的简单 Activity 类中添加

override fun onBackPressed() 
    if (supportFragmentManager.backStackEntryCount > 0) 
        Log.i(TAG, "=============onBackPressed - Popping backstack====")
        supportFragmentManager.popBackStack()
     else 
        Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
        super.onBackPressed()
    

2.在 BottomNavigationView 使用多个片段的 Activity 类中添加

override fun onBackPressed() 

    Log.e(TAG, "=============onBackPressed")
    val navController = findNavController(R.id.nav_host_fragment)
    when (navController.currentDestination!!.id) 
        R.id.navigation_comments, R.id.navigation_my_posts -> 
            menuItemPosition = 0
            navController.navigate(R.id.navigation_home)
            Log.i(TAG, "=============onBackPressed - Popping backstack with First fragment ====")
        
        else -> 
            Log.i(TAG, "=============onBackPressed called because nothing on backstack====")
            super.onBackPressed()
        
    

【讨论】:

【参考方案14】:

试试下面的代码:

@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();
            
        
    

【讨论】:

以上是关于以编程方式返回到 backstack 中的上一个片段的主要内容,如果未能解决你的问题,请参考以下文章

计时器返回到xcode中的上一个视图[重复]

从 UIDocumentBrowserViewController 中的 UserDefaults 以编程方式打开文档

当我们在android中使用backstack返回上一个片段时,上一个片段正在重新启动

如何关闭活动并返回到android中的上一个活动

导航到 Jetpack Navigation 中的另一个 Fragment 后将 DialogFragment 保留在 backstack 中

在 Android Navigation 组件中使用 backstack 打开不同层次结构中的片段