本章要点
Android为了统一界面风格,在2014年的 Google I/O 大会上推出了一套全新的界面设计语言——Material Design。
12.1 什么是Material Design
Material Design 是由Google的设计工程师们基于传统优秀的设计原则,给丰富的创意和科学技术所发明的一套全新的界面设计语言,包含了视觉,运动,互动效果等特性。
它的出现,使Android的UI界面首次超过了iOS。
为了解决面向开发者的问题,比如:很多我们的开发者不知道什么样的界面和效果叫Material Design。就算搞清楚了,实现起来也是比较困难的,于是 Google I/O 大会上推出了 Design Support 库,这个库将 Material Design 中最具有代表性的一些控件和效果进行了封装,使得我们开发者能够轻松的将自己的应用程序 Material 化。
接下来我们学习 Design Support 这个库,并且配合其他组件来完成一个优秀的Material Design 应用。
新建一个 MaterialTest 项目。
12.2 ToolBar
ToolBar是我们接触的第一个 Material Design 控件,对于它的另一个相关控件ActionBar。
ActionBar的设计被限定只能位于活动的顶部,从而不能实现 Material Design 的效果。因此官方更加推荐使用ToolBar。
ToolBar的强大之处在于,它不仅继承了ActionBar的所有功能,而且灵活性很高。
任何一个新建项目,默认都会显示ActionBar。它是根据项目中指定的主题来显示的,打开AndroidManifest.xml文件,如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
...
</application>
使用android:theme属性指定了一个AppTheme的主题。打开res/values/styles.xml文件,如下:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
这里定义了一个叫AppTheme的主题,然后指定了它的parent主题是Theme.AppCompat.Light.DarkActionBar。这个DarkActionBar是一个深色的主题,项目中自带的ActionBar就是因为指定了这个主题才出现的。
接下来我们使用ToolBar来代替ActionBar,通常Theme.AppCompat.NoActionBar(表示深色主题,将界面的主题颜色设成深色,陪衬颜色设成淡色)和Theme.AppCompat.Light.NoActionBar(表示淡色主题,将界面的主题颜色设成淡色,陪衬颜色设成深色)两种主题可选。那我们就选用淡色主题,如下所示:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
在AppTheme中重写了colorPrimary,colorPrimaryDark和colorAccent这3个属性的颜色。
现在我们已经将ActionBar隐藏起来了,使用ToolBar来代替ActionBar。修改activity_main.xml中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</FrameLayout>
使用了 xmlns:app 指定了一个新的命名空间。是由于 Material Design 是在 Android5.0 系统中才出现的,为了兼容之前老的系统,我们就必须使用app:attribute。
定义了一个Toolbar控件,它是有appcompat-v7库提供的。为了让ToolBar单独使用深色主题,这里我们使用 android:theme 属性,将Toolbar的主题指定成了ThemeOverlay.AppCompat.Dark.ActionBar。为了使Toolbar中的菜单按钮弹出的菜单项也变成淡色的主题,这里使用了 app:popupTheme ,是因为popupTheme这个属性是 Android5.0 新增的,这样我们就可以兼容 Android5.0 以下的系统了。
接下来我们修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); //将Toolbar的实例传入
}
}
这样我们就让它的外观和功能都和ActionBar一致了。运行程序如下:
Toolbar常用的一些功能,比如修改标题栏上显示的文字内容。在AndroidManifest.xml中指定,如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="Fruits">
...
</activity>
</application>
这里在activity新增了一个label属性,用于指定Toolbar显示的文字内容,如果没有指定就会默认使用application中指定的label内容,也就是我们的应用的名称。
为了丰富我们Toolbar,可以再添加 action 按钮。准备一些图片来作为按钮的图标。将它们放在 drawable-xxhdpi 目录下。创建一个 meum 文件夹。再创建一个toolbar.xml 文件,并编写代码如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/backup"
android:icon="@drawable/ic_backup"
android:title="BackUp"
app:showAsAction="always" />
<item
android:id="@+id/delete"
android:icon="@drawable/ic_delete"
android:title="Detele"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@drawable/ic_settings"
android:title="Settings"
app:showAsAction="never" />
</menu>
通过< item>标签定义 action 按钮,android:id 用于指定按钮的 id,android:icon 用于指定按钮的图标,android:title 指定按钮的文字。app:showAsAction 指定按钮显示的位置,使用app命名空间,为了能够兼容更低的系统。可选值:always(永远显示在Toolbar中,屏幕空间不足则不显示),ifRoom(屏幕空间足够的情况下显示在Toolbar中,不够则显示在菜单当中),never(永远显示在菜单中)。注意:Toolbar中的action按钮只会显示图标,菜单中的 action 只会显示文字。
修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
...
/**
* 加载toolbar.xml文件
*
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, menu);
return true;
}
/**
* 处理各个按钮的点击事件
*
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.backup:
Toast.makeText(this, "You clicked Backup", Toast.LENGTH_SHORT).show();
break;
case R.id.delete:
Toast.makeText(this, "You clicked Delete", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
Toast.makeText(this, "You clicked Settings", Toast.LENGTH_SHORT).show();
break;
default:
break;
}
return true;
}
}
重新运行程序,效果如下:
这些 action 按钮都是可以响应点击事件的。
Toolbar的功能还远远不足这些,后面我们会结合其他控件来挖掘Toolbar的更多功能。
12.3 滑动菜单
滑动菜单是 Material Design 中最常见的效果之一。
12.3.1 DrawerLayout
滑动就是将菜单选项隐藏起来,通过滑动来将菜单显示出来。
Google提供了一个DrawerLayout控件,实现滑动菜单简单又方便。
DrawerLayout的用法:它是一个布局,在布局中放入两个直接子控件,第一个子控件是显示在主屏幕中的显示内容,第二个控件是滑动菜单中显示的内容。修改activity_main.xml中的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</FrameLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#FFF"
android:text="This is Menu"
android:textSize="30sp" />
</android.support.v4.widget.DrawerLayout>
这个DrawerLayout是由 support-v4 库提供的。 我们可以看到第一个子控件FrameLayout(用于作为主屏幕显示的内容);第二个子控件TextView(作为滑动菜单中显示的内容),这个子控件中 android:layout_gravity 这个属性必须指定(滑动菜单是在屏幕的左边还是右边,left,right,这里我指定了start,根据系统语言进行判断,比如英语,汉语,滑动就在左边,阿拉伯语滑动就在右边)。
运行程序,左侧向右侧滑动,如图:
向左滑动,或者点击菜单以外的区域,都可以将滑动菜单关闭。
为了解决用户不知道这个功能,Material Design建议我们在Toolbar 的最左边接入了一个导航按钮,点击也会将滑动菜单展示出来。(这样就相当于给用户提供了良两种打开滑动菜单的方式)。
将准备好的c_menu.png放在drawable-xxhdpi目录下,修改MainActivity中的代码如下:
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mDrawerLayout= (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true); //显示导航按钮
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);//设置导航按钮图标(默认返回箭头,含义返回上一个活动)
}
}
...
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case an