概述
Material Design是Android5.0提出的一个Android及其他平台上的应用的新的设计风格。
Material Design给我们带来了一些新的控件,比如:Floating Action Button。使用它们并且能够向后兼容是一个比较麻烦的过程。为了简化流程,通常需要第三方的jar包。
在2015年的Google IO大会上,谷歌推出了Android Design Support Library,它带来了一系列的Material Design风格的控件。它向后兼容到Google2.1,并且非常容易使用。这篇文件将通过一个应用给大家介绍这些控件。
开始
你可以下载最终的项目代码:Github
在开始之前我们先设置项目及一些样式。使用Android Studio创建一个Design Demo
的项目,并且保证最低的编译版本为15.
在app模块下的build.gradle的文件中添加以下依赖:
|
|
第一行我们添加了design support librar
,第二行我们添加了一个 cardview
包,这个包后面会用到。同步gradle文件,然后下载相关的包。
在res/values
下创建一个colors.xml
文件,并添加以下内容:
|
|
修改strings.xml
文件为以下内容,这是我们最终的srings.xml
:
|
|
修改res/values/styles.xml
为以下内容:
|
|
上面的代码,我们自定义了应用的 Color Palette。
其他的主题设置在下面的图片中指明。
注意我们在上面的主题设置中并没用使用android:
前缀(比如:android:colorPrimaryDark
),因为这是为了向后兼容性。android:
需要最低21的api级别。parent theme设置为NoActionBar
是因为我们项目中使用ToolBar而不是ActionBar做为标题栏。
为了使用Toolbar我们在activity_main.xml
中添加以下内容:
|
|
上面的代码中我们删除了RelativeLayout默认的padding,并从库中添加了一个Toolbar。但是如果你的应用支持的api最低为21,那么可以直接定义一个Toolbar,而不是使用兼容支持库中的。
在MainActivity.java
中我们做如下修改:
|
|
从github下载项目所需要的drawable资源文件夹,并复制到项目的res目录中,这样上面的代码就不会出错。
确认你导入的Toolbar是支持库的。
在上面的代码中我们得到了一个Toolbar的引用并把它赋给了ActionBar。然后我们得到ActionBar的引用,并设置它的Home Icon为 infamous hamburger menu icon。
运行应用你将看到Toolbar变成了app的ActionBar。
NavigationView
NavigationView是Android中一个普通的控件,以前也有其他的解决方案,但实现过程和NavigationView相比都比较麻烦。
首先,修改activity_main.xml
的内容如下:
|
|
在上边的代码中我们在DrawerLayout中添加了一个NavigationView。在NavigationView中有两个重要的属性:app:headerLayout
指出了NavigationView的头部布局;而app:menu
指出了NavigationView的列表布局(可在运行时修改)。
在res/layout下创建一个drawer_header.xml
布局文件,内容如下:
|
|
这样就可以给NavigationView创建一个高为150的头部布局并且以我们设置的colorPrimaryDark颜色为背景。
下一步创建一个drawer.xml
在res/menu目录中,内容如下:
|
|
在上面的代码中,我们给导航界面创建了一个选择列表。第一部分是一个可以单选的列表,单选后会有高亮显示。第二部分我们用一个子标题将其和第一部分分开。
在MainActivity.java
中添加以下代码:
|
|
然后在onCreate方法的最后添加如下代码:
|
|
修改onOptionsItemSelected(MenuItem)
如下:
|
|
这样当点击Home按包的时候,就会显示导航界面。启动app你会看到以下界面:
为了获取导航栏条目的点击事件,我们需要在NavigationView
设置OnNavigationItemSelectedListener
。将以下代码添加到onCreate(Bundle)
方法的底部:
|
|
上面的代码给NavigationView添加了一个列表点击监听事件,并且在点击的时候设置被点击Item为选中状态,然后导航界面关闭,并弹出一个Toast。
在真正的项目中,就不仅公是弹出一个Toast,而可能会跳到一个Fragment。如果你再次打开导航界面,你会看到相应的条目处于高亮状态。
Floating Action Button (FAB)
FAB是一个圆形按钮用于在界面上进行重要的交互。FAB提供了一个持久的实现,默认它的颜色是应用主题设置的colorAccent
。
为了更好的和界面中的其他控件协调,FAB除了支持正常尺寸(56dp)大小,还支持MINI尺寸(40dp)大小。
添加一个FAB,可以在activity_main.xml中添加以下代码:
|
|
以上代码我们在主界面的右下角添加了一个FAB,并且通过android:src
设置了FAB的显示图片。在代码中你可以通过 setImageDrawable()
来设置显示图片。
运行APP你可以看到以下界面:
我们后面会在FAB上设置onClickListener
。
Snackbar
原来我们使用Toast对用户的操作进行快速的响应。现在有了一个新的选择:Snackbar。
Snackbar显示在界面的下面,并且有一个可选的单独的点击操作。在超时时间到达后,Snackbar会随着动画消失,用户也可以将它们滑动出界面。
因为Snackbar可以和用户进行交互和滑动隐藏,而且和Toast的api相似,所以它们被认为比Toast更加强大。
在MainActivity.java中,添加以下代码到onCreate(Bundle)
方法的底部:
|
|
在上面的代码中,我们给FAB添加了一个点击事件,当它被点击的时候,一个Snackbar会弹出,并且它会有一个点击操作。当它被点击的时候,会弹出一个Toast。
注意make()方法的第一个参数,它是一个view,这个view就是用来定位Snackbar会显示在它的底部。运行应用:
注意Snackbar是在FAB的上面,后面我们在讲CoordinatorLayout
的时候会修正这个问题。
TabLayout
在Android上有用Tabs来切换不同的Views的使用方式。Design库里的TabLayout给这种方式提供了一个简单的实现。TabLayout可以被实现成一个将界面的宽度等比分配的样式,或者一个可以横向滚动的不等比分配的样式。
在activity_main.xml
中添加以下内容来添加一个TabLayout:
|
|
上面我们添加一个TabLayout和一个ViewPager。ViewPager用来进行界面间的切换。
在MainActivity.java
中添加以下子类:
|
|
|
|
在onCreate(Bundle)
方法的最后添加以下代码:
|
|
上面我们创建了一个简单的Fragment,它的内容只是一个TextView。然后我们创建了一个FragmentStatePagerAdapter
,把它做为ViewPager的适配器。在DesignDemoPagerAdapter
类中的getCount()方法返回有多少个标签页。getItem(int)
返回将要被显示在ViewPager中的Fragment。getPageTitle(int)
返回标签栏所返回的标题。我们使用setupWithViewPager()
将TabLayout和ViewPager绑定,不管它们那个切换,另一个也会做出相应的切换。
运行应用你可以看到标签页,可以通过滑动ViewPager切换,或者点击TabLayout标签栏进行切换。
CoordinatorLayout
CoordinatorLayout
是一个设计支持库中的非常有用的控件,可以通过触摸事件控制子控件的响应。
一个例子就是把一个FAB当做一个子控件放到CoordinatorLayout中。然后我们传递CoordinatorLayout到Snackbar.make()中的第一个参数。
前面给大家演示了,Snackbar显示在FAB上面。当FAB在CoordinatorLayout中的时候,当Snackbar显示的时候FAB会自动的上移,当Snackbar消失的时候FAB会自动回到原来的位置。在Android3.0以上支持。
在activity_main.xml做以下修改来添加一个CoordinatorLayout:
|
|
从上面中以看出FAB需要成为CoordinatorLayout的一个子控件,所以我们将上面的RelativeLayout替换成一个CoordinatorLayout。同时注意我们FAB的位置android:layout_gravity="bottom|right"
以确保它在右下角。
然后在MainActivity.java中我们将CoordinatorLayout做为view参数传递给Snackbar。
|
|
运行应用,我们点击FAB,这时Snackbar显示出来,但和以前不一样FAB会随着Snackbar向上移动;然后当Snackbar消失的时候,FAB也会回到原来的位置。
CoordinatorLayout的另一个主要的使用方式是应用的标题栏滚动的时候的响应。设计支持库提供了AppBarLayout,它允许Toolbar和其他view(例如:提供标签页的TabLayout)反馈滚动事件给一个被标记为ScrollingViewBehavior的兄弟级View中。
首先我们先创建一个可以滚动的控件。我们使用RecyclerView去创建一个滚动列表。
注意:我花了一个小时使用CoordinatorLayout和ListView来配合使用,但是滚动标记并不起作用。简单的搜索我查看了这里、这里、这里。如果你查看地了这些链接,似乎CoordinatorLayout和ListView并不友好(还有GridViews
和ScrollViews
)。后面的两个链接提供了一个和ListView配合使用的方案,但是它不是向后兼容的。我这里提出来是希望你不要在同样的问题上卡住。ListViews的支持在后面的更新中可以会支持。
关于RecyclerView的使用我不做过多的解释,这不是这篇文章的内容。你可以在网上轻松的找到关于RecyclerView的使用说明。
在app模块的build.gradle文件中添加以下内容,然后同步:
|
|
添加一个布局文件:fragment_list_view.xml,然后添加以下内容:
|
|
添加另一个布局文件: list_row.xml,并把内容修改为如下:
|
|
新建一个 DesignDemoRecyclerAdapter.java 内容如下:
|
|
修改MainActivity.java中的DesignDemoFragment.onCreateView()
内容如下:
|
|
这样就可以显示前面的布局文件。现在fragment的界面就是一个列表。运行应用看下:
完成这些以后我们就可以看到CoordinatorLayout提供的滚动行为。
修改activity_main.xml如下:
|
|
在上面的代码中,我们把Toolbar和TabLayout嵌入到AppBarLayout中。AppBarLayout允许Toolbar和其他Views(例如:TabLayout)对一个标记为ScrollingViewBehavior的兄弟级控件中的滚动行为做出反馈。
当用户滚动RecyclerView,AppBarLayout会通过子控件的滚动标记进行响应进入屏幕和退出屏幕的行为。
滚动标记如下:
- scroll:如果view想滚动出屏幕,可以使用这个标记。如果不使用这个标记,View将被固定在屏幕的顶部。
- enterAlways:如果控件使用了这个标记,在向下滚动的时候这个控件将变得可见,使”快速返回”模式可用。
- enterAlwaysCollapsed:如果某个View定义了这个标记,并且设置了
minHeight
属性,这个View只会在进入的时候先显示minHeight高度,只有当滚动到屏幕的顶部的时候才会全部显示。 - exitUntilCollapsed:这个标记将会使View在退出的时候会保留
minHeight
的高度。
注意:所有使用滚动标记的控件都必须在没有使用滚动标记的控件之前声明。这个可以确保有滚动标记的控件可以在退出的时候剩下固定的控件。
在我们的应用中我们给Toolbar设置了scroll
and enterAlways
滚动标记,这样当我们向下滚动的时候Toolbar会滚出屏幕,当我们向上滚动的时候Toolbar又出现。同时需要注意在ViewPager上的app:layout_behavior="@string/appbar_scrolling_view_behavior
标记。设计支持库给我们提供了一个字符串资源@string/appbar_scrolling_view_behavior
,它就是AppBarLayout.ScrollingViewBehavior
,它会通知AppbarLayout当一个特殊的View在滚动的时候。当View触发滚动事件时,行为就必须确定。
运行应用看一下Appbar的滚动效果。
CollapsingToolbarLayout
CollapsingToolbarLayour给Appbar提供了另外一种滚动行为。为了在项目中看到,我们首先建立一个Activity,有一个Toolbar但是没有TabLayout。
创建一个空白的Activity,名为:SecondActivity
修改activity_second.xml 如下:
|
|
在上面的代码中我们使用了CollapsingToolbarLayout,并且设置了它的标记为scroll
和 exitUntilCollapsed
,这样它的子控件将会滚出屏幕。然而,我们设置Toolbar的app:layout_collapseMode=”pin”,这样就使Toolbar在View收缩的时候能够保留在屏幕的顶部。另一个效果就是CollapsingToolbarLayout的标题会变的更大,当CollapsingToolbarLayout全部显示的时候,同时在CollapsingToolbarLayout收缩的时候变成默认大小。我们在代码中设置标题。剩下的布局包含NestedScrollView和一些卡片在里面。
修改SecondActivity.java的 onCreate(Bundle)
方法如下:
|
|
这里我们设置了Toolbar的返回按钮,并且设置了CollapsingToolbarLayout的标题。
为了让返回按钮能够工作,在Manifest里的SecondActivity
的配置中添加以下元数据:
|
|
在DesignDemoRecyclerAdapter.java中修改onBindViewHolder()方法:
|
|
上面的代码中我们给RecyclerView的每一行的TextView设置了一个点击事件。这不是实现RecyclerView的Item的点击事件的最佳方式,我只是为了用最少的代码实现界面跳转。
运行app我们看到如下:
Floating Labels for EditText
设计支持库的最后一个控件是一个看起来像是一个增强型的EditText。一般情况下,当我们在EditText中进行输入时,提示语会消失。现在你可以把EditText放在一个TextInputLayout中,这样提示语就会浮现在EditText的上面,这样用户就永远可以知道他们要输入什么内容。
我们修改activity_second.xml中某个CardViews的内容如下。
|
|
运行应用可以看到以下效果:
除了显示提示语,你还可以设置错误信息显示在EditText的下面,通过setError()方法调用。
结语:
到了本教程的结尾了,完整的代码可以在这里下载。更多的Android Design Support Library信息可以参考 Android developers blog。
我的代码在这里。
附录:
Material Design使用:
作为我们开发者,最关心的还是如何在项目中使用Material Design风格:
- 设置应用的
targetSdkVersion
和targetSdkVersion
为21 - 在values目录下的style资源文件中创建一个style,让其继承自
android:Theme.Material
- 在AndroidManifest中指定应用的主题或者Activity的主题为我们设定的样式
谷歌官方我们提供了三种配色风格的Material Design样式:
- 黑色主题
Theme.Material
- 明亮主题
Theme.Material.Light
- 明亮主题黑色ActionBar
Theme.Material.Light.DarkActionBar
主题属性:
android:colorPrimaryDark
应用的主要暗色调,statusBarColor默认使用该颜色android:statusBarColor
状态栏颜色,默认使用colorPrimaryDarkandroid:colorPrimary
应用的主要色调,actionBar默认使用该颜色android:windowBackground
窗口背景颜色android:navigationBarColor
底部栏颜色android:colorForeground
应用的前景色,ListView的分割线,switch滑动区默认使用该颜色android:colorBackground
应用的背景色,popMenu的背景默认使用该颜色android:colorAccent
一般控件的选种效果默认采用该颜色android:colorControlNormal
控件的默认色调android:colorControlHighlight
控件按压时的色调android:colorControlActivated
控件选中时的颜色,默认使用colorAccentandroid:colorButtonNormal
默认按钮的背景颜色android:textColor
Button,textView的文字颜色android:textColorPrimaryDisableOnly
RadioButton checkbox等控件的文字android:textColorPrimary
应用的主要文字颜色,actionBar的标题文字默认使用该颜色
主题不仅可以对Application
和Activity
使用,也可以对某一个控件单使用,或者是在xml布局中给一个根节点控件设置android:theme属性,来修改它和它所有子控件的主题。 如果我们要对特定控件实例做自定义修改,更建议大家可以通过控件自身的API进行设置修改。
Material Design兼容性:
Material Design主题只有在API级别为21以上才可使用,在v7支持库中提供了部分控件的Material Design主题样式,如果想使应用在android的所有版本上都能统一风格,我们可以对控件效果做自定义或者使用一些第三方的兼容包。目前最有效的做法是针对21版本创建value-21资源目录,使用Material Design风格主题,在其他版本使用v7的Theme.AppCompat.Light风格主题。
注意事项:
- 在使用CardView的时候,一定要注意,当CardView的宽和高填充父容器的时候,CardView的margin最好要比cardElevation大,不然就看不到立体的效果。
- 我们知道ListView有一个onItemClick的事件,但是RecyclerView却没有,那么我们应该怎样去设置呢?其实很简单,关于RecyclerView设置item的点击事件,只需在创建ViewHolder的时候,给填充的View设置单击事件即可。
- 在使用android.support.design.widget.AppBarLayout的时候内容区最好使用android.support.v4.widget.NestedScrollView。
MD的主题色解析图:
沉浸式状态栏:
android:windowTranslucentStatus
:设置为true则状态栏变透明(4.4以上手机),此时不做任何处理会出现如图的效果:
android:fitsSystemWindows
:设置为true让Activity 中setContentView
的布局不覆盖状态栏(即相当于给状态栏设置了padding),这个属性要在根布局中使用。如果同时设置了
|
|
将使状态栏透明,标题栏不覆盖状态栏:
既然4.4以后加入了windowTranslucentStatus
属性,那我们就可以使用状态栏的区域了。所以我们就可以设置一个和状态栏等高的View,背景颜色设置成需要的颜色的就可以了。具体代码使用鸿洋大神的工具类:
|
|
如何使用:
|
|
==注意:==
创建
values-19
文件夹,并创建styles.xml
,内容如下:12345<resources><style name="AppTheme" parent="@style/BaseAppTheme"><item name="android:windowTranslucentStatus">true</item></style></resources>用来设置状态栏透明,并且可被用户使用,以使我们可以添加需要的View。
因为5.0提供了setStatusBarColor去设置状态栏颜色,但是这个方法不能在主题中设置
windowTranslucentStatus
属性。所以我们创建values-21
文件夹,并创建styles.xml
,内容如下:1234<resources><style name="AppTheme" parent="@style/BaseAppTheme"></style></resources>同时需要注意
android:fitsSystemWindows="true"
的使用。如果要控件为DrawerLayout
,我测试设置无效,需要在它的子控件中设置,并且NavigationView
中的布局不用再设置。
4.4真机实现结果: