【问题标题】:Material Design: Nav Drawer Width材料设计:导航抽屉宽度
【发布时间】:2014-12-21 03:41:56
【问题描述】:

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

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

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

我有两个部分解决方案。首先是骇人听闻的方式:在包含活动中,我输入了以下代码:

if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB_MR1) { 最终显示 display = getWindowManager().getDefaultDisplay(); 最终点大小 = new Point(); display.getSize(大小); 最终 ViewGroup.LayoutParams 参数 = mDrawerFragment.getView().getLayoutParams(); params.width = size.x - getResources().getDimensionPixelSize( R.dimen.abc_action_bar_default_height_material ); mFragmentUserList.getView().setLayoutParams(params); }

但是,这会导致第二个布局循环并且在姜饼中不起作用:它不是最佳的。

第二种解决方案涉及在片段和抽屉布局之间添加一个空间。但是,它会取代阴影和用户可以按下以返回主应用程序的位置。当按下“汉堡包”图标时,它也会崩溃。也不是最优的。

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

【问题讨论】:

    标签: android android-appcompat material-design


    【解决方案1】:

    我设法使用 XML 样式声明制作了一个解决方案,但它也有点笨拙。我的方法是使用边距而不是应用设置的宽度,以避免编写任何代码来手动计算布局。我创建了一个基本的样式规则来强调如何让它发挥作用。

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

    按照以下步骤操作:

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

      values/dimens.xml

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

      values-land/dimens.xml

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

      values/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>
      

      values-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"
      />
      

    【讨论】:

    • 应该被接受为已回答,这个信息太棒了。谢谢大佬。
    【解决方案2】:

    在寻找更简单的解决方案后,我发现了一篇非常澄清的文章:Material Navigation Drawer sizing

    这里:

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

    [以 dp 为单位的宽度] = 360dp — 56dp = 304dp

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

    [宽度 in dp] = 384dp — 56dp = 328dp

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

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

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

    你基本上总是可以在 -sw360dp 上使用 304dp 和 320dp on -sw384dp 为你的导航抽屉,你会做对的。

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • "侧边导航的宽度等于屏幕的宽度减去操作栏的高度,或者在这种情况下距屏幕右边缘 56dp。导航的最大宽度抽屉是标准增量的 5 倍(移动设备上为 56dp,平板电脑上为 64dp)。”你从哪里得到 6 * actionbarSize ?
      • 是的,它是 5,但 5 看起来不正确,而 6 看起来是文档中的错误类型。我正在寻找一种提交此文件的方法,但找不到任何方法。
      • 顺便说一句,如果你检查他们的截图并测量它,你会发现它绝对不是 5 :) google.com/design/spec/patterns/navigation-drawer.html
      【解决方案4】:

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

      需要注意的是,我的应用仅适用于手机,我选择 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】:

        Navigation Drawer 宽度取决于设备最小宽度、方向和 Android 版本。

        Check out this article about sizing Navigation Drawer.

        【讨论】:

          【解决方案6】:

          有了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),但您不能对列表项使用自定义视图。

          【讨论】:

          • 这对我来说效果很好。我认为这应该是正确的答案,因为它不需要开发人员的编码工作。然而,能够完全填充 Google 的导航抽屉宽度指南。
          • @zubietaroberto 是的,我当然知道。但仍有可能有人遇到此类问题,并且可能会觉得这很有用。
          • NavigationView 具有android:fitsSystemWindows="true" 时,此方法会导致子布局呈现在状态/导航栏下(并且没有必要的填充)。有什么好办法解决吗?
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-05-14
          • 2014-12-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多