Material Design 实战 之第一弹——Toolbar详解


本模块共有六篇文章,参考郭神的《第一行代码》,对Material Design的学习做一个详细的笔记,大家可以一起交流一下:


      写在文首,什么是Material Design?这里参考一下郭神的说法:



文章提要与总结


1. 关于android:theme的详细理解(附图);
    (运用:使用Toolbar代替ActionBar时,须将Theme.AppCompat.Light.DarkActionBar改成Theme.AppCompat.Light.NoActionBar)
2. 在activity_main.xml中使用Toolbar代替ActionBar;
        关于命名空间:android  app;
        关于Toolbar控件的属性;
                尤其android:theme以及app:popupTheme的用法理解;

3. 关于activity.android:label;

4. 通过Menu resource file菜单文件式(同时为xml格式)来为Toolbar添加action按钮;
        文件中:
        <item>标签来定义action按钮,
        android:id用于指定按钮的id,
        android:icon用于指定按钮的图标,
        android:title用于指定按钮的文字;
        使用app:showAsAction来指定按钮的显示位置,再次使用了app命名空间,同样是为了能够兼容低版本的系统;
         showAsAction的几种选值:always   ifRoom   never
        注意,
                Toolbar中的action按钮只会显示图标,
                菜单中的action按钮只会显示文字;

5. onCreateOptionsMenu()加载描述Toolbar的action按钮的Menu resource file;
    onOptionsItemSelected()方法中处理各个按钮的点击事件;

效果图:



正文


关于Toolbar

Toolbar相关于ActionBar;
不过ActionBar由于其设计原因,被限定只能位于活动的顶部,从而不能实现一些Material Design的效果,因此官方现在已经不建议使用ActionBar了。

首先要知道,任何一个新建的项目默认都是会显示ActionBar的。
ActionBar是根据项目中指定的主题来显示,
打开AndroidManifest.xml文件:

可以看到这里用android:theme指定了一个AppTheme的主题。
打开res/values/styles.xml文件可以查看其定义出处:

这里定义了一个叫AppTheme的主题并指定它的parent主题是Theme.AppCompat.Light.DarkActionBar。
DarkActionBar是一个深色的ActionBar主题,所有的新建项目中自带的ActionBar就是因为指定了这个主题才出现的。

要使用TooIbar来替代ActionBar时需要指定一个不带ActionBar的主题,
对应的通常有Theme.AppCompat.NoActionBar和Theme.AppCompat.Light.NoActionBar这两种主题可选;
其中:

  • Theme.AppCompat.NoActionBar表示深色主题,它会将界面的主体颜色设成深色,陪衬颜色设成淡色;
  • Theme.AppCompat.Light.NoActionBar表示淡色主题,它会将界面的主体颜色设成淡色,陪衬颜色设成深色。

具体可以根据情况去设置,这里主要选用淡色主题,如下所示:

观察代码中AppTheme中的属性重写:
可见这里重写了colorPrimary、colorPrimaryDark和colorAccent这3个属性的颜色。
属性指定颜色名称对应的位置,如图:

可见除了上述3个属性之外,我们还可以通过textColorPrimary、windowBackground和navigationBarCotor等属性来控制更多位置的颜色。
不过colorAccent这个属性比较特殊,它不只是用来指定这样一个按钮的颜色,而是更多表达了一个强调的意思,比如一些控件的选中状态也会使用colorAccent的颜色。

至此已将ActionBar隐藏,接下来使用Toolbar来替代ActionBar。
修改activity_main.xml:

    <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>

下面解析一下这段代码:

  1. 首先看一下第2行,这里使用xmlns:app指定了一个新的命名空间。
    正是由于每个布局文件都会使用xmlns:android来指定一个命名空间,因此我们才能一直使用android:id、android:layoutwidth等写法,
    这里指定了xmlns:app,现在便可以使用app:attribute这样的写法了。

但是为什么这里要指定一个xmlns:app的命名空间呢?
这是由于MaterialDesign是在Android5.0系统中才出现的,而很多的Material属性在5.0之前的系统中并不存在,那么为了能够兼容之前的老系统,我们就不能使用android:attribute这样的写法了,而是应该使用app:attribute

  1. 接下来定义了一个Toolbar控件,这个控件是由appcompat-v7库提供的。
    这里我们给Toolbar指定了一个id,将它的
    宽度设置为matchparent,
    高度设置为actionBar的高度,
    背景色设置为colorPrimary。

  2. 接下来,关于主题:
    由于我们刚才在styles.xml中将程序的主题指定成了淡色主题,因此Toolbar现在也是淡色主题(“蓝底(黑字)”),而TooIbar上面的各种元素就会自动使用深色主题(“(黑底)X字”),这是为了和主体颜色区别开(具体可以看文章开头对于深色浅色主题的解释)。

    在styles.xml中将程序的主题指定成了淡色主题,Toolbar现在也是淡色主题,TooIbar上面的各种元素就会自动使用深色主题

  1. 但是这个效果看起来就会很差之前使用ActionBar时文字都是白色的,现在变成黑色会很难看。那么为了能让Toolbar单独(全局是用由APPTheme制定的浅色主题的,故相对而言这里用“单独”)使用深色主题,这里我们使用android:theme属性,将Toolbar的主题指定成了ThemeOverlay.AppCompat.Dark.ActionBar。

  2. 但是这样指定完了之后又会出现新的问题,如果Toolbar中有菜单按钮,那么弹出的菜单项也会变成深色主题,这样就再次变得十分难看,于是这里使用了app:popupTheme属性单独将弹出的菜单项指定成了淡色主题。

  3. 之所以使用app:popupTheme,是因为popupTheme这个属性是在Android5.0系统中新增的,我们使用app:popupTheme的话就可以兼容Android5.0以下的系统了。

小结:

  1. 为了能够兼容之前的老系统,使用app:attribute,而不是android:attribute;
  2. 在styles.xml中将程序的主题指定成了淡色主题;
  3. 使用android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"让Toolbar单独使用深色主题;
  4. 使用app:popupTheme="@style/ThemeOverlay.AppCompat.Light"单独将弹出的菜单项指定成了淡色主题;
  5. 之所以使用app:popupTheme,是因为popupTheme这个属性是在Android5.0系统中新增的,我们使用app:popupTheme的话就可以兼容Android5.0以下的系统了。



接下来修改MainActivity:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
    }

这里,
首先用findViewByid()得到Toolbar的实例,
然后调用setSupportActionBar()方法同时传入Toolbar的实例,
至此便实现了既使用Toolbar,又让它的外观与功能都同ActionBar一致。

现在运行一下程序,效果如图:


这个标题栏虽然看上去和之前的没什么两样,但其实它已经是Toolbar而不是ActionBar了,它现在也具备了实现MaterialDesign效果的能力。



接着实战一些Toolbar比较常用的功能,比如修改标题栏上显示的文字内容,
这段文字是在AndroidManifest.xml中指定的,如下所示:

这里给activity增加了一个android:label属性,用于指定在Toolbar中显示的文字内容,
如果没有指定的话,会默认使用application中指定的label内容,也就是我们的应用名称。

接下来再添加一些action按钮来丰富Toolbar:
先准备了几张图片来作为按钮的图标,将它们放在了drawable-xxhdpi目录下;
右击res目录→New→Directory,创建一个menu文件夹;
右击menu文件夹→New→Menuresourcefile,创建一个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="Delete"
        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命名空间,同样是为了能够兼容低版本的系统。

  • showAsAction主要有以下几种值可选:
    always表示永远显示在Toolbar中,如果屏幕空间不够则不显示;
    ifRoom表示屏幕空间足够的情况下显示在Toolbar中,不够的话就显示在菜单当中;
    never则表示永远显示在菜单当中。

  • 注意,
    Toolbar中的action按钮只会显示图标,
    菜单中的action按钮只会显示文字。

接下来就是创建菜单的套路了,修改MainActivity中的代码,如下所示:

package com.example.materialtest;

import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        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,"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:
        }
        return true;
    }

}

上述代码:
在onCreate0ptionsMenu()中加载toolbar.xml这个菜单文件,
在onOptionsItemSelected()中处理各个按钮的点击事件。
重新运行一下程序,效果如图:

可见Toolbar上面现在显示了两个action按钮,这是因为
Backup按钮指定的显示位置是alway,
Delete按钮指定的显示位置是ifRoom,而现在屏幕空间充足。因此两个按钮都会显示在Toolbar中。
Settings按钮则由于指定的显示位置是never,所以显示在菜单中(点击最右边的三个小点即知)。

同时注意这些action按钮都是可以响应点击事件的!


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350