【问题标题】:Navigation drawer, handling the back button to go to previous fragments?导航抽屉,处理后退按钮以转到以前的片段?
【发布时间】:2014-02-01 07:36:12
【问题描述】:

我正在使用内置的导航抽屉来运行我的应用程序。我不太清楚如何处理后退按钮。当它被按下时,我希望它再次加载第一个片段。片段1。

因此,当应用启动时,您会看到 Fragment1 启动。然后,他们可以单击片段 2-5 转到其他页面。在所有这些页面中,我希望后退按钮将用户带回 Fragment1。用户应该能够通过返回按钮退出应用程序的唯一位置是 Fragment1。

因为这一切都是由 FragmentActivity 处理的,所以我试着在那里弄乱后退按钮。但是,我不断收到强制关闭错误:

(01-11 14:09:33.114: E/AndroidRuntime(8292): android.view.InflateException: Binary XML file line #7: Error inflating class fragment)

这是我目前所拥有的:

我已确保将片段添加到后台堆栈,如下所示:

fm.beginTransaction().replace(R.id.main, newFragment).addToBackStack("fragBack").commit();

返回按钮:

@Override
public void onBackPressed() {
    if (getSupportFragmentManager().findFragmentByTag("fragBack") != null) {
        
    }
    else {
        super.onBackPressed();
        return;
    }
    if (getSupportFragmentManager().getBackStackEntryCount() != 0) {
        Toast.makeText(getApplicationContext(), "Test", Toast.LENGTH_LONG).show();
        Fragment frag = getSupportFragmentManager().findFragmentByTag("fragBack");
        FragmentTransaction transac = getSupportFragmentManager().beginTransaction().remove(frag);
                transac.commit();
    }
    
}

有人知道我需要做什么吗?我是否需要在每个片段(如果可能的话)中调用 onBackPressed 而不是控制抽屉的 FragmentActivity ?在我过去的应用程序中,无论用户在哪个 Fragment 上,我都可以使用后退按钮关闭应用程序,但我现在正在制作的那个我希望后退按钮返回到 Fragment1。

非常感谢您的帮助,谢谢。

onItemClick

@Override
        public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
            
            Fragment newFragment = new MapsPage();
            FragmentManager fm = getSupportFragmentManager();
            switch(i) {
            case 0:
                newFragment = new Fragment2();
                break;
            case 1:
                newFragment = new Fragment3();
                break;
            case 2:
                newFragment = new Fragment4();
                break;
            case 3:
                newFragment = new Fragment5();
                break;
            }
            fm.beginTransaction().add(R.id.main, newFragment).addToBackStack("fragback").commit();
            drawerLayout.closeDrawer(rl);
        }

【问题讨论】:

  • 它应该可以在不向 onBackkeypressed 添加任何代码的情况下工作。您遇到的与布局相关的错误您也可以发布您的布局吗?
  • 真的吗?在我所有的导航抽屉中,后退按钮总是退出应用程序。无论用户选择继续使用什么 Fragment。我的布局中有自定义插件,但它是标准布局,我不认为这是我的问题,但我会发布它。
  • 在提交之前,您需要在FragmentTrasaction 中使用addToBackStack() 方法(您正在这样做)。你不需要做更多的事情,后退按钮就可以带你回到上一个片段
  • vipul也是对的,你得到的错误是你的布局文件有问题
  • 是的,只需在提交之前将 Fragment1 添加到 backstack,无论用户在哪个 Fragment 上,按下后退按钮都会将他带到 Fragment1。还要确保不要将其他 Fragments 添加到 backstack

标签: android android-fragments android-fragmentactivity navigation-drawer


【解决方案1】:

代替:

fm.beginTransaction().replace(R.id.main, newFragment).addToBackStack("fragBack").commit();

呼叫:

fm.beginTransaction().add(R.id.main, newFragment).addToBackStack("fragBack").commit();

addToBackStack 适用于add

replace 函数删除前一个片段并放置新片段,因此在您的后台堆栈中始终只有一个片段。所以使用 add 函数将之前的片段保留在堆栈中。

要始终从任何片段 onBackPress 转到 fragemnt1,请尝试执行以下操作:

getFragmentManager().popBackStack();
fm.beginTransaction().add(R.id.main, newFragment).addToBackStack("fragBack").commit();

这将从 backstack 中删除最后一个事务并添加新事务。 试试这个。

【讨论】:

  • 谢谢。这有助于让 backstack 工作。你知道我怎样才能让它总是回到 Fragment1 吗?所以他们可以转到片段 2,然后是 3,但按后退按钮会将他们带到片段 1。如果您需要,我可以发布完整的 onItemClick。
  • 这只是一个猜测 - 但是如果您在任何其他片段之间进行更改时不调用 addToBackStack() 方法(仅在离开您的片段1时调用它),那么可能会这样做它
  • 这听起来很合乎逻辑。我已经发布了我的 onItemClick 以获得更好的想法。
  • 只有从 fragment1 移动时才调用 addToBackStack
  • 我认为这里的问题可能是 Fragment 1(MapsPage) 不是导航抽屉的一部分。 (或者这不是问题吗?)。在我的代码中,当您启动应用程序时会显示片段 1,但返回它的唯一方法是返回按钮。这对我正在构建的东西很有意义。它不在导航列表中。
【解决方案2】:

只是想报告我的发现,尽管对于其他可能对已接受的答案有同样问题的人来说,这个问题有点老了。对我来说,按照接受的答案中建议的方法,使图层重叠,很快使它们变得不可读。下面的代码(改编自接受的答案)避免了覆盖,但仍将屏幕添加到后台堆栈。

fragmentManager.beginTransaction().replace(R.id.container, fragment).addToBackStack("fragBack").commit();

【讨论】:

    【解决方案3】:

    在某些情况下,您必须使用替换,然后您无法使用 addtobackstack(),因此您可以在 MainActivity 中使用此代码。在这段代码中,当你按下返回键时,你总是会转到第一个片段(我称之为 HomeFragment),当你在 HomeFragment 中时,它会询问两次从应用程序中退出的时间。

     private Boolean exit = false;
    @Override
        public void onBackPressed() {
            if (exit) {
                super.onBackPressed();
                return;
            }
    
        try {
            FragmentManager fragmentManager = getSupportFragmentManager();
            Fragment fragment = fragmentManager.findFragmentByTag("HOME");
            if (fragment != null) {
                if (fragment.isVisible()) {
                    this.exit = true;
                    Toast.makeText(this, "Press Back again to Exit", Toast.LENGTH_SHORT).show();
                }
            }
            else {
                fragment = HomeFragment.class.newInstance();
                getFragmentManager().popBackStack();
                fragmentManager.beginTransaction().replace(R.id.flContent, fragment, "HOME").commit();
            }
        } catch (Exception e) {
    
        }
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                exit = false;
            }
        }, 2000);
    }
    

    【讨论】:

      【解决方案4】:
       - @Override
             public void onBackPressed() {
                 DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                 int backstack = getSupportFragmentManager().getBackStackEntryCount();
                 if (drawer.isDrawerOpen(GravityCompat.START)) {
                     drawer.closeDrawer(GravityCompat.START);
                 } else if (backstack > 0) {
                    for (int i = 0; i < backstack; i++) {
                         getSupportFragmentManager().popBackStackImmediate();
                  }
             } else {
                 this.finish();
              }
          }
      

      【讨论】:

      • 为了改善您的答案,也许您可​​以添加一些关于您的解决方案的描述文本
      【解决方案5】:

      我有 4 个片段附加到底部导航活动 我最近遇到了这个问题并成功解决如下 我的活动代码

      import androidx.annotation.NonNull;
      import androidx.appcompat.app.AppCompatActivity;
      import androidx.fragment.app.Fragment;
      import androidx.fragment.app.FragmentTransaction;
      import androidx.navigation.NavController;
      import androidx.navigation.Navigation;
      import androidx.navigation.ui.NavigationUI;
      
      import android.os.Bundle;
      import android.view.MenuItem;
      
      import com.google.android.material.bottomnavigation.BottomNavigationView;
      
      public class BottomNavigationActivity extends AppCompatActivity
      {
          NavController navController;
          @Override
          protected void onCreate(Bundle savedInstanceState)
          {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_bottom_navigation);
      
      
              BottomNavigationView bottomNavigationView=findViewById(R.id.bottom_navigation);
              bottomNavigationView.setOnNavigationItemSelectedListener(navListener);
      
              getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,new FragmentHome()).commit();
      
      
          }
      
          public boolean onSupportNavigateUp() {
              return navController.navigateUp();
          }
      
          private BottomNavigationView.OnNavigationItemSelectedListener navListener= new
                  BottomNavigationView.OnNavigationItemSelectedListener()
                  {
                      @Override
                      public boolean onNavigationItemSelected(@NonNull MenuItem item)
                      {
      
                          Fragment selectedFragment = null ;
      
      
                          switch (item.getItemId())
                          {
      
                              case R.id.nav_home:
                                  selectedFragment = new FragmentHome();
      
                                  break;
      
                              case R.id.nav_search:
                                  BottomNavigationActivity.this.getSupportFragmentManager().beginTransaction()
                                          .addToBackStack(null)
                                          .commit();
                                  selectedFragment=new FragmentSearch();
                                  break;
      
                              case R.id.nav_cart:
                                  BottomNavigationActivity.this.getSupportFragmentManager().beginTransaction()
                                          .addToBackStack(null)
                                          .commit();
                                  selectedFragment=new FragmentCart();
                                  break;
      
                              case R.id.nav_user:
                                  BottomNavigationActivity.this.getSupportFragmentManager().beginTransaction()
                                          .addToBackStack(null)
                                          .commit();
                                      selectedFragment= new FragmentAccount();
                                              break;
      
      
                          }
      
                          getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container,
                                  selectedFragment).commit();
      
                          return true;
      
                      }
                  };
      
      
          @Override
          public void onBackPressed()
          {
              int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
              if (backStackEntryCount == 0) {
                  super.onBackPressed();
              } else
                  {
                  goHome();
              }
          }
      
          public void goHome()
          {
              //Following code will set the icon of the bottom navigation to active
              final BottomNavigationView mBottomNav = findViewById(R.id.bottom_navigation);
              MenuItem homeItem = mBottomNav.getMenu().getItem(0);
              mBottomNav.setSelectedItemId(homeItem.getItemId());
              getSupportFragmentManager().popBackStackImmediate();
      
              //To delete all entries from back stack immediately one by one.
              int backStackEntry = getSupportFragmentManager().getBackStackEntryCount();
              for (int i = 0; i < backStackEntry; i++) {
                  getSupportFragmentManager().popBackStackImmediate();
              }
              //To navigate to the Home Fragment
              final FragmentHome homeFragment = new FragmentHome();
              FragmentTransaction myFragmentTransaction = getSupportFragmentManager().beginTransaction();
              myFragmentTransaction.replace(R.id.fragment_container, homeFragment, "HomeFrag Tag");
              myFragmentTransaction.commit();
          }
      }
      

      【讨论】:

        【解决方案6】:

        我建议首先通过正确管理您的交易来完全避免覆盖onBackPressed()。这将有助于避免在未来实施疯狂的逻辑。

        首先,我们需要设置一个私有类变量来启用初始化:

        private boolean popNext = false;
        

        以下代码允许我们通过将初始返回函数放入堆栈来设置它。此后每次,当 popNext 设置为 true 时,我们弹出初始事务并推送新事务。因此,我们将 1>X 交易替换为 1>Y 交易。

        额外嵌入的 if 语句处理选择初始项目,因为我们不想从 1>1 开始。如果这是我们最初的案例,我们只需关闭抽屉。另一种情况需要像返回按钮一样,但我们需要记住将它设置为返回初始状态!

        if(popNext){
            if(i == INITIAL_POSITION){
                onBackPressed();
                mDrawerLayout.closeDrawer(mDrawerList);
                popNext = false;
                return;
            }
            getFragmentManager().popBackStackImmediate();
        }
        else{
            if(i == INITIAL_POSITION){
                mDrawerLayout.closeDrawer(mDrawerList);
                return;
            }
            popNext=true;
        }
        getFragmentManager()
        .beginTransaction()
        .replace(R.id.fragment_container, fragment)
        .addToBackStack(null)
        .commit();
        

        注意:我的代码使用 getFragmentManager() 而不是 getSupportFragmentManager(),这是一个本机函数,我相信是 Honeycomb。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-11
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多