在上一篇文章中我们详细介绍了什么是 Material Design,以及一些 MD 的风格,接下来我们就来进行实战,而 ToolBar 将会是我们第一个来进行实战的 Material 控件,虽然对 ToolBar 还不是那么熟悉,但是相信另一个相关的控件我们是非常熟悉的,那就是 ActionBar,相信这个大家都是很熟悉了,没错,活动的顶部导航的那个标题栏其实就是 ActionBar,我们之前的应用开发中一定都有 ActionBar 的相关使用,不过 ActionBar 由于其设计原因,应用有一定的局限性,比如被限定只能位于活动的顶部,从而不能实现一些 MD 风格,因此官方已经不建议使用 ActionBar 了,强力推荐使用 ToolBar,那么 ToolBar 到底好在哪里,ToolBar 的强大之处就在于,它不仅继承了 ActionBar 的所用功能,而且灵活性很高,可以配合一些其他的控件来完成一些 MD 的效果,扯淡就到这里,接下来开始演绎
新建一个 MaterialDesign 项目,我们马上开始吧
一、项目的主题默认是在哪里指定的?
首先我们要知道任何一个新建项目,默认都会显示 ActionBar,那么这个 ActionBar 到底是从哪里来的,其实这是根据项目中指定的主题来显示的,这里我们不妨打开我们新建项目的清单文件 AndroidManifest.xml 文件来看一下,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.qiudengjiao.materialdesign">
<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">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
可以看到,这里使用 android:theme 属性指定了一个 AppTheme 的主题,那么我们再具体去看看这 AppTheme 的主题是怎么定义的,打开 AppTheme 定义如下:
<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.DarkAcionBar,这个 DarkActionBar 是一个深色的 ActionBar 主题,我们之前所有的项目中自带的 ActionBar 就是因为指定了这个主题才出现的,显示效果如下图:
现在我们就要使用 ToolBar 来替代 ActionBar,因此需要指定一个不带 ActionBar 的主题,通常有如下两种主题可选:
- Theme.AppCompat.NoActionBar
- Theme.AppCompat.Light.NoActionBar
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
这里重写了 colorPrimary、colorPrimaryDark、colorAccent 这 3 个属性的颜色,那么这 3 个属性的颜色分别代表着什么位置的颜色呢?我们用语言太难描述清楚,直接上图吧,这张图大家也见过,来自 Google 官方网站,如下:
<style name="AppTheme.NoActionBar">
<!--状态栏颜色-->
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<!--控制各个控件被选中时的颜色-->
<item name="colorAccent">@color/colorAccent</item>
<!--页面背景色-->
<item name="android:windowBackground">@color/windowBackg</item>
<!--底部导航栏颜色-->
<item name="android:navigationBarColor">@color/navigationColor</item>
<!--Appbar背景色-->
<item name="android:colorPrimary">@color/colorPrimary</item>
<!--ToolBar上的Title颜色-->
<item name="android:textColorPrimary">@color/textColorPrimary</item>
<!--各个控制控件的默认颜色-->
<item name="android:colorControlNormal">@color/colorControlNormal</item>
</style>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
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="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</RelativeLayout>
这段代码不长,但里面却有不少技术点去仔细琢磨一下,首先看一下第三行,这里使用 xmlns:app 指定了一个新的命名空间,思考一下,这是由于每个布局文件都是用到 xmlns:android 来指定一个命名空间,因此我们才能一直使用 android:id、android:layout_width、android:layout_height 等写法,那么这里指定了 xmlns:app,也就是说可以使用 xmlns:attribute 这样的写法了,但是这里为什么要指定 xmlns:app 的命名空间呢,这是由于 Material Design 是在 Android 5.0 系统中才出现的,而很多的 Material 属性在 5.0 之前系统中国并不存在,那么为了能够兼容之前的老系统,我们就不能使用 android:attribute,而是使用 app:attribute
/**
* ToolBar 练习
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
}
}
这里关键代码只有两句,主要就是通过调用 setSupportActionBar() 方法将 ToolBar 的实例传入,这样我们就做到了既使用 ToolBar,又让它的外观与功能和 ActionBar 一致了,运行一下程序,效果图如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
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="@color/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:titleTextColor="#f5f0f0" />
</RelativeLayout>
修改显示文字,这里给 Activity 增加了一个 android:label 属性,用于指定 ToolBar 中显示文字的内容,如果没有指定的话,会默认显示 application 中指定的 label 内容,也就是我们的应用名称,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.qiudengjiao.materialdesign">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="你好"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?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="@mipmap/ic_launcher"
android:title="Backup"
app:showAsAction="always" />
<item
android:id="@+id/delete"
android:icon="@mipmap/ic_launcher"
android:title="Delete"
app:showAsAction="ifRoom" />
<item
android:id="@+id/setting"
android:icon="@mipmap/ic_launcher"
android:title="Setting"
app:showAsAction="never" />
</menu>
可以看到,我们通过<item>标签来定义 action 按钮,这里我们就是要注意一下 app:showAsAction 的用法,这个主要是用来指定按钮显示的位置,之所以这里再次使用了 app 的命名空间,同样是为了能够兼容低版本的系统,showAsAction 主要有三种值可选:
- always 表示永远显示在 ToolBar 中,如果屏膜空间不够则不显示
- ifRoom 表示屏膜空间足够的情况下,显示在 ToolBar 中,不够的话就显示在菜单当中,
- naver 则表示永远显示在菜单当中
/**
* ToolBar 练习
*/
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.toolbar, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.backup:
Toast.makeText(this, "Click Backup", Toast.LENGTH_LONG).show();
break;
case R.id.delete:
Toast.makeText(this, "Click Delete", Toast.LENGTH_LONG).show();
break;
case R.id.setting:
Toast.makeText(this, "Click Setting", Toast.LENGTH_LONG).show();
break;
default:
}
return true;
}
}
<android.support.v7.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/colorPrimary"
app:logo="@mipmap/ic_launcher"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:subtitle="@string/app_name"
app:subtitleTextColor="#c69aec"
app:titleTextColor="#f5f0f0" />
例如用 app:logo 来指定 app 的图标,以及用 app:subtitle 来指定副标题,app:subtitleTextColor 来指定副标题的颜色等,效果如下: