【问题标题】:Programmatically go back to the previous fragment in the backstack以编程方式返回到 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() 只会关闭我不感兴趣的活动。

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

【问题讨论】:

    标签: android android-fragments back-stack


    【解决方案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 答案

          1. 首先,调用片段管理器
          2. 之后,使用 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 个片段,没有标签,它可以很好地完成工作。

                【讨论】:

                【解决方案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();
                              }
                          }
                      }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2020-11-17
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-05-10
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多