61

我正在使用支持库中的导航抽屉模式:http: //developer.android.com/training/implementing-navigation/nav-drawer.html

我试图将其设置为始终在平板电脑上打开(作为侧面菜单)

在此处输入图像描述

当前的实现是否有可能,或者我们是否必须使用 Listview 创建新布局和新结构,而不是重用相同的代码?

4

5 回答 5

47

基于较大设备可能具有不同布局文件的想法,我创建了以下项目。

https://github.com/jiahaoliuliu/ABSherlockSlides

亮点

由于大型设备的抽屉始终可见,因此不需要抽屉。相反,具有两个同名元素的 LinearLayout 就足够了。

<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="horizontal">
     <ListView
             android:id="@+id/listview_drawer"
             android:layout_width="@dimen/drawer_size"
             android:layout_height="match_parent"
             android:layout_gravity="start"
             android:choiceMode="singleChoice"
             android:divider="@android:color/transparent"
             android:dividerHeight="0dp"
             android:background="@color/drawer_background"/>
    <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="@dimen/drawer_content_padding"
            />
</LinearLayout>

因为我们在布局文件中没有抽屉,所以当应用程序尝试在布局中查找元素时,它会返回 null。因此,不需要额外的布尔值来查看正在使用的布局。

DrawerLayout mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);

if (mDrawerLayout != null) {
    // Set a custom shadow that overlays the main content when the drawer opens
    mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
    // Enable ActionBar app icon to behave as action to toggle nav drawer
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    // ActionBarDrawerToggle ties together the proper interactions
    // between the sliding drawer and the action bar app icon
    mDrawerToggle = new ActionBarDrawerToggle(
            this,
            mDrawerLayout,
            R.drawable.ic_drawer,
            R.string.drawer_open,
            R.string.drawer_close) {

        public void onDrawerClosed(View view) {
            super.onDrawerClosed(view);
        }

        public void onDrawerOpened(View drawerView) {
            // Set the title on the action when drawer open
            getSupportActionBar().setTitle(mDrawerTitle);
            super.onDrawerOpened(drawerView);
        }
    };

    mDrawerLayout.setDrawerListener(mDrawerToggle);
}

这是将其用作布尔值的示例。

@Override
protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    if (mDrawerLayout != null) {
        mDrawerToggle.syncState();
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    if (mDrawerLayout != null) {
        // Pass any configuration change to the drawer toggles
        mDrawerToggle.onConfigurationChanged(newConfig);
    }
}
于 2013-09-25T14:36:59.140 回答
32

基于 CommonsWare 的回答,您可以通过一些调整来做到这一点。首先是设置以下三行:

drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
isDrawerLocked = true;

DrawerNoShadow 颜色可以是非 alpha 颜色(如 0x00000000)。这为您提供了一个没有背景覆盖的开放式抽屉。

您需要做的第二件事是调整 FrameLayout 的 padding_left 值。为此,您可以设置一个尺寸来控制它(默认为 0dp) - 在本例中为 R.dimen.drawerContentPadding。您还需要一个 R.dimen.drawerSize 值,该值将是 DrawerLayout 的宽度。

这允许您检查 FrameLayout 的 paddingLeft 值以调用这些行。

FrameLayout frameLayout = (FrameLayout)findViewById(R.id.content_frame);
if(frameLayout.getPaddingLeft() == (int)getResources().getDimension(R.dimen.drawerSize) {
    drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
    drawerLayout.setScrimColor(getResources().getColor(R.color.drawerNoShadow));
    isDrawerLocked = true;
}

然后,您可以将不想启用的所有功能包装在if(!isDrawerLocked)语句中。这将包括:

  • drawerLayout.setDrawerListener(drawerToggle);
  • getActionBar().setDisplayHomeAsUpEnabled(true);

最后,您确实需要使用静态抽屉为视图设置备用布局。一个例子是:

<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.DrawerLayout

    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- The navigation drawer -->
    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="@dimen/drawerSize"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>

</android.support.v4.widget.DrawerLayout>
<FrameLayout
    android:id="@+id/content_frame"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginLeft="@dimen/drawerContentPadding"/>

这里的美妙之处在于,您可以通过为您想要定位的设备设置备用 dimen.xml 文件来控制所有逻辑,您唯一需要更改的是抽屉内容填充的值并提供修改后的布局。

注意:我最终使用了 margin_left 而不是 padding_left 因为在新布局中它覆盖了抽屉。在http://derekrwoods.com/2013/09/creating-a-static-navigation-drawer-in-android/上查看有关该技术的更深入的博客文章

于 2013-08-07T05:12:52.293 回答
14

尝试setDrawerLockMode()在大屏幕设备上锁定抽屉打开。

正如我在评论中指出的那样,我认为这不是DrawerLayout为您的场景设计的(尽管这不是一个坏主意,恕我直言)。要么使用不同的布局来承载相同的ListView内容,要么下载并修改您自己的副本DrawerLayout,在大屏幕设备上,在打开时滑动内容而不是重叠内容。

于 2013-06-16T13:02:16.440 回答
9

只需为平板电脑提供备用布局文件。这样,您可以保存所有的默认行为NavigationView


步骤1

只需为平板设备创建一个与此类似的备用布局文件并将其放在layout-w600dp-land资源目录中。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <!--
    NavigationView and the content is placed in a horizontal LinearLayout
    rather than as the direct children of DrawerLayout.
    This makes the NavigationView always visible.
    -->

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <android.support.design.widget.NavigationView
            android:id="@+id/nav"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:headerLayout="@layout/nav_header_main"
            app:menu="@menu/activity_main_drawer"/>
        <include
            layout="@layout/app_bar_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>

</android.support.v4.widget.DrawerLayout>



第2步

在这一步中,我们将进行足够的更改以确保抽屉的打开和关闭仅适用于非平板设备。

步骤 2.1

将以下内容添加到values目录下的新值资源文件中并命名config_ui.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isDrawerFixed">false</bool>
</resources>

那是针对非平板设备的。对于平板设备,创建另一个具有相同名称的设备并将其放在values-w600dp-land.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <bool name="isDrawerFixed">true</bool>
</resources>

在抽屉所属的活动类中创建一个新字段 as
private boolean isDrawerFixed;
并将其初始化为
isDrawerFixed = getResources().getBoolean(R.bool.isDrawerFixed);

现在我们可以检查设备是平板电脑还是非平板电脑,就像if (isDrawerFixed){}.

步骤 2.2

if用这样的语句包装在操作栏上设置切换按钮的代码。

if (!isDrawerFixed) {
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.addDrawerListener(toggle);
    toggle.syncState();
}

使用类似这样的另一个if语句包装当单击项目时关闭抽屉的代码。

if (!isDrawerFixed) {
    drawer.closeDrawer(GravityCompat.START);
}




最终的结果看起来有点像这样。

输出

于 2018-06-01T15:26:48.410 回答
7

以前的答案很好,但是我在项目中实现它们时遇到了一些问题,所以我想分享我的解决方案。首先,我们需要定义一个自定义抽屉:

public class MyDrawerLayout extends DrawerLayout {
    private boolean m_disallowIntercept;

    public MyDrawerLayout (Context context) {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(final MotionEvent ev) {
        // as the drawer intercepts all touches when it is opened
        // we need this to let the content beneath the drawer to be touchable
        return !m_disallowIntercept && super.onInterceptTouchEvent(ev);
    }

    @Override
    public void setDrawerLockMode(int lockMode) {
        super.setDrawerLockMode(lockMode);
        // if the drawer is locked, then disallow interception
        m_disallowIntercept = (lockMode == LOCK_MODE_LOCKED_OPEN);
    }
}

然后我们把它放在一个基本的活动布局中(没有以前答案的任意布局),如下所示:

<MyDrawerLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <!--We must define left padding for content-->
    <FrameLayout
        android:id="@+id/content_frame"
        android:paddingStart="@dimen/content_padding"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <android.support.design.widget.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:menu="@menu/menu_nav" />

</MyDrawerLayout>

对于 NavigationView,此处的内容填充在纵向方向为 0dp,在横向方向为大约 300dp(根据经验计算)。我们在适当的values文件夹中定义它们:

values/dimens.xml-

<dimen name="content_padding">0dp</dimen>

values-land/dimens.xml-

<dimen name="content_padding">300dp</dimen>

最后,我们将抽屉锁定在活动中:

    if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
        mDrawerLayout.setScrimColor(0x00000000); // or Color.TRANSPARENT
        isDrawerLocked = true;
    } else if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
        mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
        mDrawerLayout.setScrimColor(0x99000000); // default shadow
        isDrawerLocked = false;
    }
于 2017-05-29T06:26:29.717 回答