导航抽屉,处理后退按钮以转到以前的片段?

Posted

技术标签:

【中文标题】导航抽屉,处理后退按钮以转到以前的片段?【英文标题】: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 【参考方案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。

【讨论】:

以上是关于导航抽屉,处理后退按钮以转到以前的片段?的主要内容,如果未能解决你的问题,请参考以下文章

使用导航组件处理工具栏后退按钮

后退按钮关闭应用程序而不是转到上一个片段 android 导航组件

在本机反应中处理设备后退按钮

Android Studio - 带回栈的导航抽屉

当用户按下后退按钮时隐藏导航抽屉

设置导航 backBarButtonItem 以转到 Swift 中的特定 UIViewController