Android – Toolbar 上的 Navigation Drawer

来源 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"
                 xmlns:tools= "http://schemas.android.com/tools"
                 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 上,如下图:

NavDrawer over 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
   xmlns:tools= "http://schemas.android.com/tools"
   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 设计了另外一种样式出来,差异请见下图:

NavDrawer

嗯,简言之,状态栏是半透明的状态,而侧边栏可以被看到。要调整的地方有二,

一在 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 的人在本篇中给予留言,做认证喽 :

最後,附上本篇所有範例的程式連結,還請大家多多指教嘍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值