材料设计:导航抽屉宽度
Posted
技术标签:
【中文标题】材料设计:导航抽屉宽度【英文标题】: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 的解决方案?
【问题讨论】:
【参考方案1】:我设法使用 XML 样式声明制作了一个解决方案,但它也有点笨拙。我的方法是使用边距而不是应用设置的宽度,以避免编写任何代码来手动计算布局。我创建了一个基本的样式规则来强调如何让它发挥作用。
不幸的是,DrawerLayout 目前应用的最小边距为 64dp。为了使这种方法起作用,我们需要用负边距来抵消该值,以便我们可以获得导航抽屉所需的宽度。希望将来可以解决此问题 (Someone has filed an issue regarding it),这样我们就可以参考 abc_action_bar_default_height_material
尺寸参考作为边距。
按照以下步骤操作:
添加以下维度和样式定义:
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>
在项目中添加上述规则后,您可以在导航抽屉视图中引用 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_
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_
android:layout_
android:id="@+id/navdrawer_layout"
android:fitsSystemWindows="true">
<!-- Layout where content is shown -->
<RelativeLayout
android:layout_
android:layout_>
<include android:id="@+id/toolbar"
layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/content_frame"
android:layout_
android:layout_
android:layout_below="@id/toolbar" />
<!-- Toolbar shadow for pre-lollipop -->
<View style="@style/ToolbarDropshadow"
android:layout_
android:layout_
android:layout_below="@id/toolbar" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_
android:layout_
android:layout_gravity="start">
<ListView
android:id="@+id/navdrawer_list"
android:layout_
android:layout_
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"
时,此方法会导致子布局呈现在状态/导航栏下(并且没有必要的填充)。有什么好办法解决吗?以上是关于材料设计:导航抽屉宽度的主要内容,如果未能解决你的问题,请参考以下文章
当按下后退按钮并打开导航抽屉时,我的应用程序关闭而不是关闭抽屉