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

Posted

技术标签:

【中文标题】禁用导航抽屉,在片段中切换主页按钮/向上指示器【英文标题】:Disabling navigation drawer, toggling home-button/up-indicator in fragments 【发布时间】:2013-10-26 16:29:00 【问题描述】:

设置

我有一个 Activity,它的 contentView 是 DrawerLayout 的一个实例,它有一个抽屉式导航栏,在操作栏中显示了一个抽屉式指示器。该活动包含一个Fragment,我们称之为ListFragment,其中包含一个选项列表。单击选项时,我将ListFragment 替换为DetailFragment

此时,我想显示一个“向上”导航选项,而不是抽屉式导航指示器。如果我通过调用mDrawerToggle.setDrawerIndicatorEnabled(false) 禁用抽屉指示器,我可以显示“向上”图标,但这只会删除抽屉图标——它不会删除功能——也就是说,当我单击插入符号时,导航抽屉仍处于打开状态。

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

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

我也实现了Switching between android Navigation Drawer image and Up caret when using fragments 中的步骤。它在显示插入符号时起作用,但尽管覆盖了向上按钮功能,但菜单仍然打开(应用程序确实导航回 - 它也只是打开了抽屉)。

问题

所以,长话短说:当我的布局根是 DrawerLayout 时,是否有任何(最好是干净优雅,但此时我将使用 hacky)方法来实现这些事情:

    用“向上”插入符号替换抽屉指示器(暂时可以通过mDrawerToggle.setDrawerIndicatorEnabled(false)) 防止在单击插入符号时打开抽屉,而是使用我自己的“向上”功能覆盖 当我从屏幕边缘拖动时,防止抽屉打开。

编辑

好吧,看起来如果我同时覆盖 ActionBarDrawerToggleonOptionsItemSelected,当我单击插入符号时菜单不会打开。但如果我从边缘拖动它仍然会打开。救命!

【问题讨论】:

嗨,我遇到了同样的问题。但是我通过在 ActionBarSherlock 中设置一些选项来修复它,并且我认为在使用股票 ActionBar 时也可以执行相同的方式。那么你当时使用过这些 ActionBar 吗? 是的,我使用的是股票 ActionBar。 你是什么意思:我覆盖了 ActionBarDrawerToggle?你重写了哪些方法? 对不起,那是很久以前的事了,我现在不记得了。你遇到了什么问题? 【参考方案1】:

短代码

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 生成的 NavigationDrawerFragement。这让我可以在切换片段之前调用它。 很好,对我有帮助。唯一的问题是onDrawerStateChanged 参数应该是DrawerLayout.STATE_* 之一。非常感谢! 使用这个 public boolean isDrawerOpen() return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(Gravity.LEFT); public void closeDrawer() mDrawerLayout.closeDrawer(Gravity.LEFT); 公共无效 openDrawer() mDrawerLayout.openDrawer(Gravity.LEFT); 私有 void closeMenu() if ( mDrawerLayout != null ) closeDrawer(); 【参考方案2】:

这只是我找到的解决方案的一部分,但很难找出这个错误,所以为了后代,我把它留在这里。

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

<ListView
    android:id="@+id/listview_drawer"
    android:layout_
    android:layout_
    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" 后,这个问题似乎得到了解决。

我能够在仅导航抽屉的示例应用中重现此问题,因此它似乎是一个可重现的问题,并非我的情况所独有。

【讨论】:

谢谢!有同样的问题 @Catherine “示例,navigation-drawer-only 应用” 是否可以在线获得? 不,但我可能有它,如果你需要它,我可以将它上传到 Github 上。顺便说一句,你的一堆编辑是错误的——grammarbook.com/punctuation/dashes.asp 和“insofar”是一个词。 :P 你这么容易解决了一个相当大的问题。感谢您的更新:)【参考方案3】:

以索尼达的回答为基础。在调用 setDrawerIndicatorEnabled(false) 之后,仍然没有调用 onNavigateUp。所以,我刚刚创建了一个新的 onClickListener 来调用它:

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(); 这对我有用【参考方案4】:

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

使用以下基于已给出的代码构建的代码来禁用滑动

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

【讨论】:

【参考方案5】:

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

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

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

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

@Override
public void onDestroyView()
    // Say, using an implemented interface Make call to MainActivitiy's setNavigationDrawerState() passing true 
    // setNavigationDrawerState(true)

    super.onDestroyView();

【讨论】:

以上是关于禁用导航抽屉,在片段中切换主页按钮/向上指示器的主要内容,如果未能解决你的问题,请参考以下文章

在 Android Studio 的默认导航抽屉模板中使用按钮在片段之间切换

如何使向上按钮返回而不是打开导航抽屉

从片段中禁用导航抽屉

Android导航组件“向上按钮”打开抽屉导航

导航抽屉 - 禁用点击抽屉后面的项目

Android如何使用工具栏中的按钮切换以使用片段打开/关闭导航抽屉