1.1 Android 5.0新特性
Android 5.0 Lollipop是 Google于2014年10月15日发布的Android操作系统。北京时间2014年6月26日,Google I/O 2014开发者大会在旧金山正式召开,发布了Android 5.0的开发者预览版。下面我们先来看看Android 5.0给我们带来了什么。
1.1.1 Android 5.0主要新特性概述
作为一个 Android开发者,我们需要了解最近的 Android版本带来了什么特性,这样更有利于开发。谷歌(Google)在Android 5.0中带给我们很多惊喜。
1.全新的 Material Design设计风格
Material Design是一种大胆的平面化创新(见图1-1)。换句话说,谷歌希望能够让Material Design给用户带来纸张化的体验。这种新的视觉语言,在基本元素的处理上,借鉴了传统的印刷设计,以及字体版式、网格系统、空间、比例、配色和图像使用等这些基础的平面设计规范。另外,Material Design还推崇实体隐喻理念,利用实体的表面与边缘的质感打造出视觉线索,让用户感受到真实性。熟悉的触感让用户可以快速地理解并认知。在设计中可以在符合物理规律的基础上灵活地运用物质,打造出不同的使用体验。为了吸引用户的注意力,Material Design还带来了有意义而且更合理的动态效果,以及维持整个系统的连续性体验。需要注意的是Material Design虽然是在 Android 5.0时被提出来的,但是它也是在不断更新的,所以关于Material Design的内容会在第2章专门介绍。

图1-1 Material Design
2.支持多种设备
Android系统的身影早已出现在多种设备中,比如:智能手机、平板电脑、笔记本电脑、智能电视、汽车、智能手表甚至是各种家用电子产品等。
3.全新的通知中心设计
谷歌在Android 5.0中加入了全新风格的通知系统。改进后的通知系统会优先显示对用户来说比较重要的信息,而将不太紧急的内容隐藏起来。用户只需要向下滑动就可以查看全部的通知内容,如图1-2所示。
4.支持 64位 ART虚拟机
Android 5.0内部的性能上也提升了不少,它放弃了之前一直使用的Dalvik虚拟机,改用了ART虚拟机,实现了真正的跨平台编译,在ARM、X86、MIPS等无处不在。
5.Overview
多任务视窗现在有了一个新的名字,Overview。在界面中,每一个App都是一张独立的卡片,拥有立体式的层叠效果,用户可以设定“最近应用程序”,通过滑动来快速切换 App,如图1-3所示。

图1-2全新的通知中心设计

图1-3全新的“最近应用程序”
6.设备识别解锁
现在个人识别解锁已经被普遍使用,比如当特定的智能手表出现在Android设备的附近时,就会直接绕过锁屏界面进行操作。而Android 5.0也增加了这种针对特定设备识别解锁的模式。换句话说,当设备没有检测到附近有可用的信任设备时,就会启动安全模式以防止未授权访问。
7.Ok Google语音指令
当手机处于待机状态时,对你的手机轻轻说声“Ok Google”,手机即刻被唤醒,只需说出简单的语言指令,如播放音乐、查询地点、拨打电话和设定闹钟等,一切只需“说说”而已。
8.Face unlock面部解锁
在Android 5.0中,Google花费大力气优化了面部解锁功能。当用户拿起手机处理锁屏界面上的消息通知时,面部解锁功能便自动被激活。随意浏览几条消息之后,手机已经默默地完成了面部识别。
1.1.2替换ListView和GridView的RecyclerView
有了 ListView、GridView,为什么还需要 RecyclerView这样的控件呢?从整体上看,RecyclerView架构提供了一种插拔式的体验,它具有高度的解耦、异常的灵活性和更高的效率,通过设置它提供的不同LayoutManager、ItemDecoration、ItemAnimator可实现更加丰富多样的效果。但是RecyclerView也有缺点和让人头疼的地方:设置列表的分割线时需要自定义,另外列表的点击事件需要自己去实现。
1.配置build.gradle
要想使用RecyclerView,我们首先要导入support-v7包。因为我用的是Android Studio(本书的所有例子均基于Android Studio),所以在此需要在build.gradle中加入如下代码以自动导入support-v7包,记得配置完再重新Build一下工程。

2.使用RecyclerView

与ListView不同的一点就是,需要设置布局管理器用于设置条目的排列样式,可以是垂直排列或者水平排列。这里我们设置setLayoutManager(new LinearLayoutManager(this))表示条目是线性排列的(默认是垂直排列的)。

如果想要设置为水平排列,可以按如下代码所示编写:

此外,RecyclerView比ListView的设置要复杂一些,主要是它需要自己去自定义分割线,设置动画和布局管理器,等等。布局文件activity_recycler_view.xml如下:

Adaper最大的改进就是对ViewHolder进行了封装定义,我们只需要自定义一个ViewHolder继承RecyclerView.ViewHolder就可以了。另外,Adaper继承了 RecyclerView.Adapter,在onCreateViewHolder中加载条目布局,在onBindViewHolder中将视图与数据进行绑定。


在HomeAdapter的onCreateViewHolder方法中我们加载了条目的样式文件item_recycler。它的布局很简单,就是显示一个文字。

运行程序效果如图 1-4所示。从图 1-4中可以看出,这里没有分割线,有些难看。下面我们来讲一讲分割线。

图1-4不带分割线的纵向排列列表
3.设置分割线
我们可以使用mRecyclerView.addItemDecoration()来加入分割线。谷歌目前没有提供默认的分割线,这就需要我们继承RecyclerView.ItemDecoration来自定义分割线。



这里核心的方法就是onDraw方法,它根据传进来的orientation来判断是绘制横向item的分割线还是纵向item的分割线。其中,drawHorizontal用于绘制横向item的分割线,drawVertical用于绘制纵向item的分割线。getItemOffsets方法则用于设置item分割线的size。虽然没有默认的分割线,但是好处我们也发现了:那就是我们可以更灵活地自定义分割线。实现自定义的分割线,我们只要在setAdapter之前加入如下代码便可加入分割线,如图1-5所示。


图1-5带分割线的纵向排列列表
4.自定义点击事件
列表中条目的点击事件需要我们自己来定义,这是一个不尽如人意的地方。但是,自定义点击事件也并不是很难。在Adaper中定义接口并提供回调,我们在这里定义了条目的点击事件和长按点击事件。

接下来对item中的控件进行点击事件监听并回调给我们自定义的监听,如下所示:

最后在Activity中进行监听:


长按时会弹出对话框,删除时会有消失的动画,如图1-6所示。

图1-6自定义点击事件
5.实现GridView
只需要自定义横向的分割线,然后在代码中设置:

很明显,这里设置一行显示条目为4个,其实现效果如图1-7所示。

图1-7 GridView
6.实现瀑布流
虽然第三方实现的瀑布流已经很不错了,但是谷歌这次提供的RecyclerView支持瀑布流,我们没有理由不去用。因为它更稳定、效率更高、自定义能力更强。这里为了实现方便,我们可以不用写mRecyclerView.addItemDecoration(new DividerGridItemDecoration(this))来设置分割线,可以在item布局文件中定义分割距离android:layout_margin=”2dp”:

实现瀑布流很简单,只要在Adaper写一个随机的高度来控制每个 item的高度就可以了。通常这个高度是由服务端返回的数据高度来控制的,在这里我们写一个随机的高度来控制每个item的高度:

接着我们在Adaper的onBindViewHolder中设置每个item的高度,效果如图1-8所示。

图1-8简单实现瀑布流
1.1.3卡片CardView
Android 5.0版本中新增了CardView,CardView继承自FrameLayout类,并且可以设置圆角和阴影,使得控件具有立体性,也可以包含其他的布局容器和控件。
1.配置build.gradle
如果 SDK低于 5.0,我们仍旧要引入 v7包。在 build.gradle中加入如下代码以自动导入support-v7包。记得配置完再重新Build一下工程。

2.使用CardView
先来看看布局,代码如下所示:


这里有两个CardView的重要属性:card_view:cardCornerRadius,设置圆角的半径;card_view:cardElevation,设置阴影的半径。
除此之外,CardView还有其他属性,在这里就不做实现了。其他属性如下所示。
• CardView_cardBackgroundColor:设置背景色。
• CardView_cardElevation:设置Z轴阴影。
• CardView_cardMaxElevation:设置Z轴最大高度值。
• CardView_cardUseCompatPadding:是否使用CompadPadding。
• CardView_cardPreventCornerOverlap:是否使用PreventCornerOverlap。
• CardView_contentPadding:内容的padding。
• CardView_contentPaddingLeft:内容的左padding。
• CardView_contentPaddingTop:内容的上padding。
• CardView_contentPaddingRight:内容的右padding。
• CardView_contentPaddingBottom:内容的底padding。
接着来看看Java代码。


在这里设置了3个seekBar分别来设置CardView:mCardView.setRadius()设置圆角的半径,mCardView.setCardElevation()设置阴影的半径,mCardView.setContentPadding()设置CardView中的子控件和父控件的距离。运行程序,效果如图1-9所示。

图1-9 CardView
1.1.4 3种Notification
Notification可以让我们在获得消息的时候,在状态栏,锁屏界面来显示相应的信息。如果没有Notification,那我们的QQ和微信以及其他应用没法主动通知我们,我们就需要时时地看手机来检查是否有新的信息和提醒,这着实让人烦心。这一点也体现出Notification的重要性。这里会介绍3种Notification,分别是普通Notification、折叠式Notification和悬挂式Notification。
1.普通Notification
首先创建Builder对象,用PendingIntent控制跳转,这里跳转到网页。

有了builder,我们就可以给Notification添加各种属性了:

普通Notification(普通通知)如图1-10所示。

图1-10普通Notification
2.折叠式Notification
折叠式Notification是一种自定义视图的Notification,用来显示长文本和一些自定义的布局场景。它有两种状态:一种是普通状态下的视图(如果不是自定义的话,和上面普通Notification的视图样式一样),另一种是展开状态下的视图。和普通Notification不同的是,我们需要自定义视图,而这个视图显示的进程和我们创建视图的进程不在一个进程,所以我们需要使用RemoteViews。首先要使用RemoteViews来创建我们的自定义视图。

视图的布局文件:


然后,我们需要把自定义的视图赋值给Notification的视图,如下代码是把自定义视图赋值给Notification展开时的视图:

当然,我们也可以把自定义视图赋值给Notification普通状态时的视图,如下所示:

其他的代码和普通Notification没什么区别,折叠式Notification的完整代码如下所示:

如果不是自定义普通状态视图的话,折叠式Notification(折叠式通知)普通状态下和普通Notification(普通通知)没什么区别,如图1-11所示。我们接着往下拉,使折叠式Notification完全展开就会出现我们自定义的视图,如图1-12所示。

图1-11普通状态下的折叠式Notification

图1-12展开状态下的折叠式Notification
3.悬挂式Notification
悬挂式Notification是Android 5.0新增加的方式。和前两种显示方式不同的是,前两种需要下拉通知栏才能看到通知;而悬挂式Notification不需要下拉通知栏就直接显示出来悬挂在屏幕上方,并且焦点不变,仍在用户操作的界面,因此不会打断用户的操作。其过几秒就会自动消失。和前两种Notification不同的是,它需要调用setFullScreenIntent来将Notification变为悬挂式Notification。

实现悬挂式Notification的完整代码:

悬挂式Notification(悬挂式通知)运行效果如图1-13所示。
4.Notification的显示等级
Android 5.0加入了一种新的模式Notification的显示等级,共有以下3种。
• VISIBILITY_PUBLIC:任何情况都会显示通知。
• VISIBILITY_PRIVATE:只有在没有锁屏时会显示通知。
• VISIBILITY_SECRET:在pin、password等安全锁和没有锁屏的情况下才能够显示通知。

图1-13悬挂式Notification
设置非常简单,只要调用setVisibility方法就可以了:
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
我在这里写了一个方法来设置Notification等级,用radioGroup来演示Notification的各个显示等级,详情请参照源码。

1.1.5 Toolbar与Palette
对于已经被不大好用的Actionbar“折磨”的开发者来说,Toolbar的出现确实是一个好消息。Toolbar是应用内容的标准工具栏,可以说是Actionbar的升级版。这两者不是独立关系,要使用Toolbar,还是得跟Actionbar有关系的。相比于Actionbar,Toolbar最明显的一点就是变得很自由,可随处放置,其具体使用方法和Actionbar很类似。
1.引入Toolbar
我们首先还是要引入v7支持包,在build.gradle中配置如下代码:

接下来为了显示Toolbar控件,先要在style里把Actionbar去掉,如下所示:

设置各个部分属性,如图1-14所示。

图1-14 Toolbar设置各个部分属性
接着写一个 mytoolbar.xml,引入 Toolbar控件。这么写的目的是方便多次调用,我们可以在其他布局中用include引用此布局。

在主界面布局用 include引用 mytoolbar.xml中的 Toolbar,在主界面布局中我们用DrawerLayout来完成侧滑的效果。


接下来在Java代码中设定Toolbar,代码如下所示:

是不是很容易?当然Toolbar能做的不只这些,接下来试试自定义Toolbar。
2.自定义Toolbar
当然,我们还可以设置Toolbar的标题和图标以及Menu Item等属性。Menu Item的设置和Actionbar类似,我们在menu/main.xml中去声明,代码如下所示:

然后覆写onCreateOptionsMenu并在toolbar.setOnMenuItemClickListener实现点击MenuItem的回调,代码如下所示:
@Override

3.添加DrawerLayout实现侧滑
DrawerLayout实现侧滑很简单,这里因为是介绍 Toolbar的,所以就不实现稍微复杂的效果了。


程序运行效果如图1-15所示,DrawerLayout展开效果如图1-16所示。

图1-15 DrawerLayout未展开效果

图1-16 DrawerLayout展开效果
4.Palette的应用
这次Android 5.x用Palette来提取颜色,从而让主题能够动态适应当前界面的色调,做到整个App颜色的基调和谐统一。Android内置了几种提取色调的种类:
• Vibrant(充满活力的)
• Vibrant dark(充满活力的黑)
• Vibrant light(充满活力的亮)
• Muted(柔和的)
• Muted dark(柔和的黑)
• Muted light(柔和的亮)
要使用Palette,我们需要引用’com.android.support:palette-v7:23.0.1’。这在之前已经配置过了,实现提取颜色非常容易,只要将bitmap传递给Palette,调用generate即可。在onGenerated回调中得到图片的色调,这里我们获取的是图片充满活力的色调,最后我们把Toolbar的背景设置为该图片的色调。
