禁用导航抽屉,在片段中切换主页按钮/向上指示器

48

设置

我有一个活动,其contentView是DrawerLayout的一个实例,其中包含一个带有抽屉指示器的导航抽屉栏。该活动包含一个Fragment,让我们称之为ListFragment,它包含选项列表。当单击某个选项时,我会将ListFragment替换为DetailFragment

应用程序的架构

此时,我想显示“上一个”导航选项,而不是导航抽屉指示符。如果我通过调用mDrawerToggle.setDrawerIndicatorEnabled(false)禁用抽屉指示符,则能够显示“向上”图标,但这只是删除了抽屉图标 - 它没有删除功能 - 也就是说,当我单击插入符号时,导航抽屉仍然打开。

此外,在这些子视图中,我想通过从屏幕边缘拖动来禁用抽屉的打开。我尝试通过调用setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)来实现此操作,但似乎并没有禁用此功能。

我尝试扩展ActionBarDrawerToggle类以防止在单击指示器时打开抽屉 - 但是,所有发生的事情仅是执行覆盖操作(“向上”导航),但是抽屉仍然打开。

我还实现了在使用片段时在Android导航抽屉图像和向上符号之间切换中的步骤。就显示插入符号而言,它有效,但是尽管覆盖了向上按钮的功能,菜单仍然打开(应用程序确实导航回去 - 它只是同时打开了抽屉)。

问题

长话短说:是否有任何方法(最好是干净而优雅的方法,但此时我将选择hacky方法)可以在我的布局根为DrawerLayout的情况下实现这些内容:

  1. 使用“向上”指示符替换抽屉指示符(通过mDrawerToggle.setDrawerIndicatorEnabled(false)可能可以实现)
  2. 防止在单击指示符时打开抽屉,代之以自己的“向上”功能。
  3. 防止当我从屏幕边缘拖动时打开抽屉。
  4. 编辑

    好的,看起来如果我同时覆盖ActionBarDrawerToggleonOptionsItemSelected,菜单不会在我点击指示符时打开。但是如果我从边缘拖动,它仍然会打开。请帮忙!


嗨,我遇到了同样的问题。但是我通过在ActionBarSherlock中设置一些选项来解决它,我认为在使用原始的ActionBar时也可以采用相同的方法。那么你当时使用过这些ActionBar中的任何一个吗? - dumbfingers
是的,我正在使用默认的ActionBar。 - Catherine
你说的"I ovverride ActionBarDrawerToggle"是什么意思?你重写了它的哪些方法? - edoardotognoni
抱歉,那是很久以前的事了,我现在记不清了。你遇到了什么问题? - Catherine
5个回答

34

简码

public void setDrawerState(boolean isEnabled) {
    if ( isEnabled ) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);
        drawerToggle.setDrawerIndicatorEnabled(true);
        drawerToggle.syncState();

    }
    else {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        drawerToggle.setDrawerIndicatorEnabled(false);
        drawerToggle.syncState();
    }
}

它运行了!我在由Android Studio生成的NavigationDrawerFragment中实现了这个。这使我能够在切换片段之前调用它。 - Lachlan Ennis
1
非常好,它帮助了我。唯一的问题是onDrawerStateChanged的参数应该是 DrawerLayout.STATE_* 中的一个。非常感谢! - Marek
使用以下代码:public boolean isDrawerOpen() { return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.LEFT); }public void closeDrawer() { mDrawerLayout.closeDrawer(Gravity.LEFT); }public void openDrawer() { mDrawerLayout.openDrawer(Gravity.LEFT); }private void closeMenu() { if (mDrawerLayout != null) { closeDrawer(); } } - sonida

22

这只是我找到的解决方案的部分内容,但要找出这个错误非常困难,所以我把它留在这里供后人参考。

这是我为我的导航抽屉定义ListView的方法:

<ListView
    android:id="@+id/listview_drawer"
    android:layout_width="240dp"
    android:layout_height="match_parent"
    android:layout_gravity="start|bottom"
    android:background="#111"
    android:choiceMode="singleChoice"
    android:divider="@android:color/transparent"
    android:dividerHeight="0dp" />

在调用setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)之后,我仍然能够拖动抽屉打开。

但是,将layout_gravity更改为"start"后,这个问题似乎得到了解决。

我能够在一个只有导航抽屉的应用中重现这个问题,因此它看起来是一个可再现的问题,不仅仅局限于我的情况。


谢谢!我遇到了相同的问题。 - Thermometer
@Catherine,“仅包含导航抽屉的示例应用程序”是否可以在线获取? - JJD
1
不过,我可能有它的备份,并且如果你需要的话可以上传到Github上。顺便说一下,你的一堆编辑都是错的——http://www.grammarbook.com/punctuation/dashes.asp,“insofar”应该是一个单词。:P - Catherine
你轻易地解决了一个相当大的问题。 感谢更新 :) - Ninja_Coder

12

在sonida的回答基础上进行扩展。调用setDrawerIndicatorEnabled(false)后,onNavigateUp仍未被调用。因此,我只需创建一个新的onClickListner来调用它:

public void setDrawerState(boolean isEnabled) {
    if ( isEnabled ) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        drawerToggle.setDrawerIndicatorEnabled(true);
        drawerToggle.syncState();

    }
    else {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
        drawerToggle.setDrawerIndicatorEnabled(false);
        drawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onSupportNavigateUp();
            }
        });
        drawerToggle.syncState();
    }
}

我认为

drawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);

已经被弃用,但在没有它的情况下也可以正常工作。


我使用了 onBackPressed(); 而不是 onSupportNavigateUp();,这对我起作用了。 - Cobbles

2

您需要禁用滑动和禁用操作栏主页按钮:

使用以下代码,基于已经给出的代码来禁用滑动:

  public void setDrawerState(boolean isEnabled) {
        if ( isEnabled ) {
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
            mDrawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_UNLOCKED);
            mDrawerToggle.setDrawerIndicatorEnabled(true);
            mDrawerToggle.syncState();
            getActivity().getActionBar().setHomeButtonEnabled(true);

        }
        else {
            mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
            mDrawerToggle.onDrawerStateChanged(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
            mDrawerToggle.setDrawerIndicatorEnabled(false);
            mDrawerToggle.syncState();
            getActivity().getActionBar().setHomeButtonEnabled(false);
        }
    }

1

在@sonida的答案基础上,并使用@luca992和@jai提供的调整后,进行构建。

我尝试了上面建议的代码,但是左侧操作栏中的“向上”或“返回”箭头在我的应用程序中根本没有显示出来。但幸运的是,我能够解决这个问题。

我不得不在setNavigationDrawerState()中添加这行额外的代码[参考:android.support.v7.app.ActionBarDrawerToggle.setHomeAsUpIndicator]

toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);

我从Material.io下载了drawable:ic_keyboard_backspace_white_24dp。

这是完整的代码:

MainActivity.java -> onCreate()

DrawerLayout drawer;
ActionBarDrawerToggle toggle;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // Start: Code automatically generated by Android Studio
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();
    // End: Code automatically generated by Android Studio

    // I had to add this listener as the "back" arrow was totally unresponsive
    // Thanks to @luca992
    toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            onBackPressed();
        }
    });

    // Start: Code automatically generated by Android Studio
    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
    // End: Code automatically generated by Android Studio

    // More custom code for other stuff
    // ...
}

MainActivity.java -> setNavigationDrawerState()

MainActivity.java -> 设置导航抽屉状态()

public void setNavigationDrawerState(boolean isEnabled) {
if ( isEnabled ) {
    drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
    toggle.setDrawerIndicatorEnabled(true);
    toggle.syncState();
}
else {
    drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
    toggle.setDrawerIndicatorEnabled(false);
    // the extra line of code goes here
    toggle.setHomeAsUpIndicator(R.drawable.ic_keyboard_backspace_white_24dp);    

    toggle.syncState();
}

MainActivity.java -> onBackPressed()

主活动.java -> 返回按键()
@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else if(getSupportFragmentManager().getBackStackEntryCount() > 0){
        getSupportFragmentManager().popBackStack();
    }else {
        super.onBackPressed();
    }
}

MainActivity.java -> startFragment() [示例中的虚拟函数]

public void startFragment(){
    MyFrag myFrag = new MyFrag();

    getSupportFragmentManager()
        .beginTransaction()
        .replace(R.id.frag_container ,myFrag)
        .addToBackStack(null)
        .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE)
        .commit();
}

MyFrag.java --> onViewCreated()

我的Frag.java --> onViewCreated()
@Override
public void onViewCreated (View view, Bundle savedInstanceState){
    super.onViewCreated(view, savedInstanceState);

    // Say, using an implemented interface Make call to MainActivitiy's  setNavigationDrawerState() passing false
    // setNavigationDrawerState(false)

    // ...
}

MyFrag.java --> onDestroyView()

我的Frag.java文件 --> onDestroyView()函数
@Override
public void onDestroyView(){
    // Say, using an implemented interface Make call to MainActivitiy's setNavigationDrawerState() passing true 
    // setNavigationDrawerState(true)

    super.onDestroyView();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接