在 Material Design 釋出後,Google 也開始陸續更新了 Google app 的介面,讓大家有個範例可以看。而過去大力推動的 actionbar 自然而然也成了眾開發者觀注的部份;其中的 up button 的設定在前一篇所介紹的 Toolbar 也已看到。這邊還未提到的一個部份是 material design 中有提到的人機互動效果,簡言之,就是讓使用者明顯地感受到在操作 app 時,可以獲得明顯的回應,從而得到豐富地操作體驗感;因此,在剛開始釋出的幾支 Google app 裡,大家一定都有留意到開啟 navigation drawer 時,up button 從選單圖示 (menu/hamburger icon) 旋轉成倒退圖示 (back icon) 的新效果了!

先來看到效果:

相信大家也都會很好奇這個效果要如何實作,會不會很麻煩?所幸,這個效果,被放進 support v7 之中,我們只要拿來用即可。在本篇中將分下列幾個部份,來帶大家無痛地寫出這個效果來。

  1. 實作
  2. Material design guideline 定義的 Side Drawer
  3. 其他議題

本篇所使用到的程式碼,請到 Github 下載。

1. 實作


我們馬上就開始從 navdrawer_deom_checkpoint0 開始 (這份程式碼其實就是在 Toolbar Step By Step – 調色 階段完成的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
15
16
17
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
28
29
30
31
32
33
34
<android.support.v4.widget.DrawerLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  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 設計了另外一種樣式出來,差異請見下圖:

嗯,簡言之,狀態列是半透明的狀態,而側邊欄可以被看到。要調整的地方有二,一在 layout – activity_main.xml:

 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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
14
15
16
<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
15
16
17
<!-- 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 的人在本篇中給予留言,做認證嘍  

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

2014/10/29 更新

剛巧,在同一天 Roman Nurik 在官方部落貼出了一篇 android app 的 material design 確認項目表,其中在 Navigation drawer 的部份也很明確的提到,drawer 就是以最新的釋出的樣式為標準,也就是 drawer 會覆蓋在 app bar 之上,被壓於 status bar 之下,最好還可以將 status bar 設定成半套明的樣子。

這樣的定義也有不少人問到,那這樣該 icon 都被蓋住了,要其動態效果何用?這個問題,Roman 在其 G+ 的貼文「Google I/O App Source Updated for Android 5.0 SDK」中做了如此的回應:「there are other situations where that animation can be used, e.g. moving from a top level section to a detail screen. More generally, I’d optimize for consistency and rational layering before optimizing for cool animations.」大抵的意思就是,該動畫還是會有地方可以被使用到,像是從上層 “移動” 到其下一層時。就算定義出很酷的動態效果,還是會以整體的層次感做為優先考量。

總歸來說,navigation drawer 的呈現,就是以下方這張由 Roman 定義好的樣式為標準啦!至於怎麼實作,還請往上看到實作說明嘍 =]


至於為什麼有些有 navigation drawer 的 Google app 未遵從這樣的標準呢?忘了在哪一篇 G+ 裡面有看到,Roman 有回覆說,因為程式架構的關係還在調整,未來會朝這個標準來更新之。

ANDROID – TOOLBAR 上的 NAVIGATION DRAWER(转)的更多相关文章

  1. Android官方终于支持 Navigation Drawer(导航抽屉)模式

    在2013 google IO当天,Android团的更新了Support库,新版本(V13)的Support库中新加入了几个比较重要的功能. 添加 DrawerLayout 控件,支持创建  Nav ...

  2. Android 学习笔记:Navigation Drawer

    laylout文件: <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com ...

  3. Android开发UI之Navigation Drawer

    http://blog.csdn.net/xyz_lmn/article/details/12523895

  4. Android UI开发第三十二篇——Creating a Navigation Drawer

    Navigation Drawer是从屏幕的左侧滑出,显示应用导航的视图.官方是这样定义的: The navigation drawer is a panel that displays the ap ...

  5. Android设计和开发系列第二篇:Navigation Drawer(Develop)

    Creating a Navigation Drawer THIS LESSON TEACHES YOU TO: Create a Drawer Layout Initialize the Drawe ...

  6. [Android]Android Design之Navigation Drawer

    概述 在以前ActionBar是Android 4.0的独有的,后来的ActionBarSherlock的独步武林,对了还有SlidingMenu,但是这个可以对4.0下的可以做很好的适配.自从Goo ...

  7. Navigation Drawer介绍

    在2013 google IO当天,Android团的更新了Support库,新版本(V13)的Support库中新加入了几个比较重要的功能. 添加 DrawerLayout 控件,支持创建  Nav ...

  8. Navigation Drawer(导航抽屉)

    目录(?)[-] 创建一个导航抽屉 创建抽屉布局 初始化抽屉列表 处理导航项选点击事件 监听导航抽屉打开和关闭事件 点击应用图标来打开和关闭导航抽屉 创建一个导航抽屉 导航抽屉是一个位于屏幕左侧边缘用 ...

  9. Creating a Navigation Drawer 创建一个导航侧边栏

    The navigation drawer is a panel that displays the app’s main navigation options on the left edge of ...

随机推荐

  1. Spring JDBC StoredProcedure类示例

    org.springframework.jdbc.core.StoredProcedure类是RDBMS存储过程的对象抽象的超类.这个类是抽象的,目的是让子类将提供一个用于调用的类型化方法,该方法委托 ...

  2. 使用“mvn site-deploy”部署站点(WebDAV例子)

    这里有一个指南,向您展示如何使用“mvn site:deploy”来自动部署生成的文档站点到服务器,这里通过WebDAV机制说明. P.S 在这篇文章中,我们使用的是Apache服务器2.x的WebD ...

  3. 使用jenkins配置.net mvc网站进行持续集成

    最近好久没有更新文章了,因为好久没有写代码了,以至于我不知道同大家分享些什么,刚好,今天突然叫我学习下jenkins每日构建,我就把今天的学习笔记记录下来,这其中很多东西都是公司同事之前调研总结的,我 ...

  4. IE9出现异常SCRIPT5011:不能执行已释放Script的代码

    今天同事测试系统,突然出现一个异常SCRIPT5011:不能执行已释放Script的代码 应用场景:用模态方式打开个窗口,对于返回对象使用"=="与字符串比较时出现错误 我也用我的 ...

  5. 在Centos7下发布.NET CORE项目[转]

    1.安装安装前准备开发环境 编译类库:yum -y install gcc make gcc-c++ openssl-devel 系统信息: CentOS Linux release 7.2.1511 ...

  6. dubbo学习过程、使用经验分享及实现原理简单介绍

    一.前言 部门去年年中开始各种改造,第一步是模块服务化,这边初选dubbo试用在一些非重要模块上,慢慢引入到一些稍微重要的功能上,半年时间,学习过程及线上使用遇到的些问题在此总结下. 整理这篇文章差不 ...

  7. memcached监控工具

    最简单和最直接的方式是在启动memcached的时候加入-vv参数,从而在控制台打印每次客户端的请求和相应,这非常适合开发.另外一种较为直接的方式是通过telnet进行查看,例如:若server为本机 ...

  8. SELECT a.loginname,a.deviceid,a.time,Row_Number() OVER (partition by a.loginname ORDER BY a.deviceid desc,a.time asc) rank

    现在做一个反欺诈内容要用到笛卡尔积,用来分析用户一个手机号,对应的多个设备,每个更换设备的时间,这里取的时间是系统收集时间,用来代表更换的时间, 所以要先对设备换的时间作排序,然后进行rank,最后求 ...

  9. sed在替换的时候,使用变量中的值?如何在sed实现变量的替换?获取到变量中的值?

    需求描述: 今天在做nrpe配置的时候,想要通过批量的方式来将定义文件中的IP给替换掉 开始做的时候没有成功,报错了.在此记录下,如何实现,获取到变量的值,然后 进行替换. 操作过程: 1.原文件的内 ...

  10. Go语言图形界面开发:Go版GTK

    https://www.cnblogs.com/tennysonsky/p/8433888.html package main import ( "os" "github ...