材料设计:导航抽屉宽度

时间:2014-10-25 12:46:19

标签: android android-appcompat material-design

根据the Material Design specs,导航设备上的导航抽屉宽度必须

  

侧导航宽度=屏幕宽度 - 应用栏高度

我们如何在android上实现这个?

我有两个部分解决方案。首先是hacky方式:在包含活动中我放了这个代码:

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) {
    final Display display = getWindowManager().getDefaultDisplay();
    final Point size = new Point();
    display.getSize(size);

    final ViewGroup.LayoutParams params = mDrawerFragment.getView().getLayoutParams();
    params.width = size.x - getResources().getDimensionPixelSize(
        R.dimen.abc_action_bar_default_height_material
    );
    mFragmentUserList.getView().setLayoutParams(params);
}
然而,这会导致第二个布局周期并且在姜饼中不起作用:它不是最佳的。

第二种解决方案是在片段和drawerLayout之间添加一个空格。然而,它取代了阴影和用户可以按下以返回主应用程序的位置。当" hamburguer"按下图标。也不是最佳的。

是否有更好的解决方案,最好是涉及样式和xml的解决方案?

6 个答案:

答案 0 :(得分:32)

我设法使用XML样式声明来制作解决方案,但它也有点hacky。我的方法是使用边距而不是应用设置宽度来避免编写任何代码来手动计算布局。我已经创建了一个基本的样式规则,以突出显示如何使其工作。

不幸的是,DrawerLayout目前应用的最小边距为64dp。要使这种方法起作用,我们需要使用负边距来抵消该值,以便我们可以获得导航抽屉所需的宽度。希望将来可以解决这个问题(Someone has filed an issue regarding it),这样我们就可以参考边距的abc_action_bar_default_height_material维度参考。

请按照以下步骤操作:

  1. 添加以下维度和样式定义:

    值/ dimens.xml

    <!-- Match 56dp default ActionBar height on portrait orientation -->
    <dimen name="nav_drawer_margin_offset">-8dp</dimen>
    

    值-脊/ dimens.xml

    <!-- Match 48dp default ActionBar height on landscape orientation -->
    <dimen name="nav_drawer_margin_offset">-16dp</dimen>
    

    值/ styles.xml

    <!-- Nav drawer style to set width specified by Material Design specification -->
    <style name="NavDrawer">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_marginRight">@dimen/nav_drawer_margin_offset</item>
    </style>
    

    值-sw600dp / styles.xml

    <!-- Margin already matches ActionBar height on tablets, just modify width -->
    <style name="NavDrawer">
        <item name="android:layout_width">320dp</item>
        <item name="android:layout_marginRight">0dp</item>
    </style>
    
  2. 在项目中添加上述规则后,您可以在导航栏视图中引用 NavDrawer 样式:

    layout / navigation_drawer.xml (或用于导航栏的其他适当视图)

    <?xml version="1.0" encoding="utf-8"?>
    <ListView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/navigation_drawer"
        style="@style/NavDrawer"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#FFF"
    />
    

答案 1 :(得分:28)

使用Android Design Support Library现在实现导航抽屉非常简单,包括正确的大小调整。使用NavigationView并使用其从菜单资源中取出抽屉的功能(例如here),或者您可以将其包裹在当前用于显示抽屉列表的视图周围(例如ListView,RecyclerView )。然后NavigationView将为您完成抽屉尺寸调整。

以下是我如何使用围绕ListView的NavigationView的示例:

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

    <!-- Layout where content is shown -->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <include android:id="@+id/toolbar"
            layout="@layout/toolbar" />

        <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@id/toolbar" />

        <!-- Toolbar shadow for pre-lollipop -->
        <View style="@style/ToolbarDropshadow"
            android:layout_width="match_parent"
            android:layout_height="3dp"
            android:layout_below="@id/toolbar" />

    </RelativeLayout>

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start">

        <ListView
            android:id="@+id/navdrawer_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:choiceMode="singleChoice"
            android:dividerHeight="0dp"
            android:divider="@null"/>

    </android.support.design.widget.NavigationView>

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

这样您就可以使用NavigationViews大小调整并仍然使用您自己的抽屉列表。虽然从菜单资源中创建抽屉列表要容易得多(例如here),但您无法对列表项使用自定义视图。

答案 2 :(得分:8)

在寻找更简单的解决方案后,我找到了一篇非常明确的文章:Material Navigation Drawer sizing

下面:

  

Nexus 5屏幕是一个不错的640 x 360 dp(xxhdpi),还有一个app栏   它高56 dp。所以导航抽屉应该是:

     
    

[dp中的宽度] = 360dp - 56dp = 304dp

  
     

Nexus 4采用640 x 384 dp(xhdpi)屏幕   代替。相同的56dp应用栏高度。它的导航抽屉?

     
    

[dp中的宽度] = 384dp - 56dp = 328dp

  
     

那么,Google设计师是如何提出的呢   分别是288dp和304dp的宽度?我不知道。

     

谷歌应用程序   另一方面,似乎同意我的数学。哦,你知道的是什么   最有趣的是这一切? iPhone(有不同的屏幕   高度,但恒定的320 dp宽度)正确标记为具有   264dp导航抽屉。

基本上,它表明有关导航抽屉的一些指导自相矛盾,您可以使用以下规则来避免计算:

您基本上可以在-sw360dp上使用304dp 和导航抽屉上的-sw384dp为320dp,你就能搞定。

答案 3 :(得分:4)

他们已经更新了规格,现在导航抽屉的宽度为:

Math.min(screenWidth — actionBarSize, 6 * actionBarSize);

答案 4 :(得分:0)

我发现这很难理解和实施。不幸的是,Matthew的解决方案使我的导航抽屉对于横向而言太宽了,这似乎与谷歌的做法相反,即导航宽度由设备的最小宽度决定。无论如何,因为我在清单中禁用了配置,所以在我的情况下它不起作用。所以我决定使用以下代码动态更改导航宽度。

应该注意我的应用程序仅用于手机,我确定320dp是最大宽度。这也是我为两个方向确定56dp工具栏高度的原因。

希望它对某人有所帮助,并且他们可以避免它给我带来的不必要的压力。

navDrawLayout.post(new Runnable()
    {

        @Override
        public void run() {

            Resources r = getResources();

            DisplayMetrics metrics = new DisplayMetrics();

            if(r.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){

                getWindowManager().getDefaultDisplay().getMetrics(metrics);
                int height = metrics.heightPixels;

                float screenWidth = height / r.getDisplayMetrics().density;
                float navWidth = (screenWidth - 56); 

                navWidth = Math.min(navWidth, 320); 

                int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());

                DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams(); 
                params.width = newWidth; 
                navDrawLayout.setLayoutParams(params);      


            }

            if(r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {

            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            int width = metrics.widthPixels;

            float screenWidth = width / r.getDisplayMetrics().density;
            float navWidth = screenWidth - 56; 

            navWidth = Math.min(navWidth, 320); 

            int newWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, navWidth, r.getDisplayMetrics());

            DrawerLayout.LayoutParams params = (DrawerLayout.LayoutParams) navDrawLayout.getLayoutParams(); 
            params.width = newWidth; 
            navDrawLayout.setLayoutParams(params); 


            }
        }

    }
    ); 

答案 5 :(得分:0)

导航抽屉宽度取决于设备最小宽度,方向和Android版本。

Check out this article about sizing Navigation Drawer.