来源 http://blog.mosil.biz/2014/10/navigation-drawer-on-toolbar/
ToolBar的基础知识请先阅读:android:ToolBar详解(手把手教程)
在 Material Design 发布后,Google 也开始陆续更新了 Google app 的界面,让大家有个范例可以看。而过去大力推动的 actionbar 自然而然也成了众开发者观注的部份;其中的 up button(返回上一级) 的设置在前一篇所介绍的 Toolbar 也已看到。这边还未提到的一个部份是 material design 中有提到的人机交互效果,简言之,就是让使用者明显地感受到在操作 app 时,可以获得明显的回应,从而得到丰富地操作体验感;因此,在刚开始放出的几支 Google app 里,大家一定都有留意到开启 navigation drawer 时,up button 的旋转动画效果。
先来看看效果:
相信大家也都会很好奇这个效果要如何实现,会不会很麻烦?所幸,这个效果,被放进 support v7 之中,我们只要拿來用即可。在本篇中将分下列几个部份,来带大家轻松实现这种效果来。
本篇所使用到的程式码,请到 Github 下载。
1. 实作
我们马上从 navdrawer_deom_checkpoint0 开始 (这份代码其实在 android:ToolBar详解(手把手教程) 一文的自定义颜色一节完成的toolbar_demo_checkpoint2),
在 activity_main.xml 中加入 DrawerLayout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<RelativeLayout xmlns:android=
"http://schemas.android.com/apk/res/android"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
tools:context=
".MainActivity"
>
<android.support.v7.widget.Toolbar
android:id=
"@+id/toolbar"
... />
<android.support.v4.widget.DrawerLayout
android:id=
"@+id/drawer"
android:layout_height=
"match_parent"
android:layout_width=
"match_parent"
android:layout_below=
"@+id/toolbar"
>
<!-- Content -->
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
...
</RelativeLayout>
<!-- Side Drawer -->
<LinearLayout
android:id=
"@+id/drawer_view"
android:layout_width=
"@dimen/navdrawer_width"
android:layout_height=
"match_parent"
android:layout_gravity=
"start"
android:background=
"#88FFFFFF"
android:orientation=
"vertical"
>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
|
加入后,请记得将原本在 Toolbar 控件之前的 TextView 放到<!-- Content --> 部份,做 DrawerLayout 其中的內容界面,否则在忘记放入 Content 界面的状況下,关闭侧边栏时,会发生「java.lang.NullPointerException: Attempt to invoke virtual method ‘android.view.ViewGroup$LayoutParams android.view.View.getLayoutParams()’ on a null object reference
这样的错误讯息。
在 drawer_view 中,要记得 layout_gravity 设定成 start 或是 left 。
activity_main.xml 完整程式码请见 github。
再来,就是到 MainActivity.java 中去实作 DrawerLayout,部份程式码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// 打開 up button
getSupportActionBar().setDisplayHomeAsUpEnabled(
true
);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer);
// 實作 drawer toggle 並放入 toolbar
mDrawerToggle =
new
ActionBarDrawerToggle(
this
, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerToggle.syncState();
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
|
完成后,就可以看到如上方影像一样的效果了!
完整程式码请见:navdrawer_demo_checkpoint1
2. Side Drawer
一开始,Material Design 设计文档 中,其实是没有看到侧边栏的相关说明,一直到 2014.10 才以「Side Nav」之名,加述于导览文件之中。而这个定义中的 Side Nav 画面,其实跟原本在 actionbar 的阶段是不太一样的,drawer layout 会压在 toolbar 上,如下图:
目前在 Google app 的界面中,还是以前一种为多,而现下 (2014.10) 如同 material design 在 side nav 呈现的界面还不多。
接下来就用 navdrawer_demo_checkpoint1 做为这个阶段的开始往下进行,需要调整就只有界面 (activity_main.xml) 的部份:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<android.support.v4.widget.DrawerLayout
android:id=
"@+id/drawer"
android:layout_height=
"match_parent"
android:layout_width=
"match_parent"
tools:context=
".MainActivity"
>
<!-- Content -->
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<android.support.v7.widget.Toolbar
android:id=
"@+id/toolbar"
... />
...
</RelativeLayout>
<!-- Side Drawer -->
<LinearLayout
android:id=
"@+id/drawer_view"
android:layout_width=
"@dimen/navdrawer_width"
android:layout_height=
"match_parent"
android:layout_gravity=
"start"
android:clickable=
"true"
android:background=
"#88FFFFFF"
android:orientation=
"vertical"
>
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
|
将 DrawerLayout 改到这个 layout 的 root 层,并将 toolbar 移到 content 的 layout 中,这样就可以达到这样的效果了。
需要注意的是地方在 Side 的 layout 要设定 clickable 的属性设定为 true,否则会在侧边栏打开的状况下,还能按到位于界面下方的 up button。
But!人生就是这个 but!
在前一阵子,Google 的设计师为 Google I/O 2014 设计了另外一种样式出来,差异请见下图:
嗯,简言之,状态栏是半透明的状态,而侧边栏可以被看到。要调整的地方有二,
一在 layout – activity_main.xml:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<android.support.v4.widget.DrawerLayout
...
android:fitsSystemWindows=
"true"
...>
<!-- Content -->
...
<!-- Side Drawer -->
<LinearLayout
...
android:fitsSystemWindows=
"true"
... >
</LinearLayout>
</android.support.v4.widget.DrawerLayout>
|
在 root 层的 drawer layout 跟 side drawer 的 layout 各别加上 android:fitsSystemWindows="true" 这个属性
另外一个要改的地方是在 v21/styles.xml
1
2
3
4
5
|
<style name=
"AppTheme"
parent=
"AppTheme.Base"
>
...
<!--Status bar color-->
<item name=
"android:statusBarColor"
>
#88009688</item>
</style>
|
加入一个有透明度的色码给 android:statusBarColor 这个状态列颜色设定属性。
这样就可以完成这个阶段的程式了。
完整程式码请见:navdrawer_demo_checkpoint2
3. 其他议题
Navigation icon 切换的效果,除了旋转以外,还有另外一种效果,请看下方的影像:
3.1 Navigation icon effect
左上角的切换效果变成线条的的聚合,同时 icon 的颜色也被改为黑色,这个设定只要在 /res/values/styles.xml 做如下设定
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<style name=
"AppTheme.Base"
parent=
"Theme.AppCompat"
>
...
<!--將新加入的風格 AppTheme.MyDrawerStyle 設定給 drawerArrowStyle 這個屬性-->
<item name=
"drawerArrowStyle"
>@style/AppTheme.MyDrawerArrowStyle</item>
</style>
<!--加入一個新的 navigation drarwer 的風格-->
<style name=
"AppTheme.MyDrawerArrowStyle"
parent=
"Widget.AppCompat.DrawerArrowToggle"
>
<!--將 spinBars 屬性設定為
false
-->
<item name=
"spinBars"
>
false
</item>
<!--設定 drawer arrow 的顏色-->
<item name=
"color"
>@android:color/black</item>
</style>
|
先加入针对 navigation icon 设定的风格: AppTheme.MyDrawerArrowStyle ,其继承自 Widget.AppCompat.DrawerArrowToggle 这个风格。
以本范例来说,这个风格裡设定了两个属性:
spinBars
旋转效果
false。由此可之,其预设的旋转效果预设值就是 true 了。
color
设定 navigation icon 的颜色。
增加后,再回到 AppTheme.Base 风格中,将此风格设定给 drawerArrowStyle 即可看到效果了。
3.2 Shadows
在影像中,大家应该可以看到,这个范例中还有一处跟之前不同了,内容为 Hello world! 的 TextView 变成黑色了!哦!当然不是要为各位介绍这个以前就有属性。要请各位留意的是在 TextView 周围有一圈淡淡的影子,还有在 Toolbar 也因为下方的影子,看起来较有立体感。而这也就是在 Material design 中有提到的其中一个部份:Shadows。
在过去这个效果需要自己去设定 drawable,现在只要设定个属性即可。请到 activity_main.xml 中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<!-- Content -->
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
>
<android.support.v7.widget.Toolbar
...
android:elevation=
"10dp"
... />
<TextView
...
android:elevation=
"10dp"
android:background=
"@android:color/black"
.../>
</RelativeLayout>
|
最主要就是针对 android:elevation 这个属性设定,而这个属性的意义也如同其字面的意义,他是在承述相较于底层的高度而被创造出来的阴影。而另外,在这段程式码中,特别将 TextView 中的 android:background 也列出来的原因,就是要让大家知道,android:elevation 这个属性要能够生效,该介面元件的背景属性也需要设定哦!
完整程式码请见:navdrawer_demo_checkpoint3
4. 一点想法
新的 navigation drawer 在 material design 的 side nav 裡有著跟过去不同的样式,而在 Google app 中,包含文中提到那种新的呈现样式算来,共有三重风格。这应该也意谓著,以 Google 在 side nav 在 android app 的呈现上,给予了这些弹性在。换句话说,这样看来,目前看到的这三种样式在 android app 上来看,都可以算是 material design。
也许有人会问,那导览文件是写好玩的吗?以个人的观点来看,那个的确是一个规范,是 Google 想要在不同的平台上有一个共通的范畴得以依循。因此,相信未来在 Google 的产品中,于 web、iOS 以及其他装置的介面,都会以 material design 做为标准,而设计出统一的 Google app 的体验。
而在 android 装置上,嘿嘿…毕竟是 Google 定义的嘛~那自然这部份的弹性就多于其他平台喽。所以,私以为就别太过纠结于导览文件上的定义,只要符合目前所看到的三种样式,应该都可以被视 android 装置上的 material design 啦。大家也可以放宽心的运用这三种样式去做 android app 的设计喽。
当然,以上纯粹个人观点,不代表官方立场,除非有 Google 的人在本篇中给予留言,做认证喽 :
最後,附上本篇所有範例的程式連結,還請大家多多指教嘍。