Toolbar使用之正确姿势

  • 前言

近期在公司做一个全新项目,自然在每个页面都有一个标题栏,脑海中涌出的第一想法肯定是采用Toolbar来实现,然后开始疯狂撸码,结果发现各种碰壁,比如:
1.navigationIcon与左边的间距如何调整?
2.title与navigationIcon间距如何调整?
3.Toolbar中如何使用SearchView?
4.SearchView如何自定义颜色图标文字等?
....
带着这么多疑问开始各种查阅资料,然而里面好多问题之前都遇到并解决过,无奈又忘记了,老是花时间做重复的事情显得有些愚蠢,故抽时间将这些知识点整理一下,既方便自己后续查看也方便广大开发者可以有一个集中的参考。

首先我们得知道ActionBar是Android 3.0的产物,Toolbar是Android 5.0的产物(我没记错吧?),因为ActionBar在国内各大厂商的定制系统下呈现出各种无法统一的效果,故Toolbar的出现,无疑是要一统江湖,取缔ActionBar。OK那就送走ActionBar。

  • 开发环境

AndroidStudio 3.0.1

  • 各类控件所在包

//均在appcompat包
Toolbar:  android.support.v7.widget.Toolbar
SearchView:  android.support.v7.widget.SearchView
//添加依赖
implementation 'com.android.support:appcompat-v7:26.1.0'
//均在design包
CollapsingToolbarLayout:  android.support.design.widget.CollapsingToolbarLayout
AppBarLayout:  android.support.design.widget.AppBarLayout
//添加依赖
implementation 'com.android.support:design:26.1.0'
  • 新建项目默认样式

用studio新建一个Empty Activity项目长这个样子的:
image.png
  • 修改主题支持Toolbar

默认Application主题的父亲是DarkActionBar,这样我们是不能直接在布局文件里面嵌套Toolbar的,否则会报错:

    <!-- Base application theme. -->
    <style name="CustomAppTheme" 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>

故,我要给它换一个爹: NoActionBar,这样便可以使用Toolbar:

    <!-- Base application theme. -->
    <style name="CustomAppTheme" 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>

点开NoActionBar看看里面的内容:

    <style name="Theme.AppCompat.Light.NoActionBar">
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

再次运行App,效果如下!感觉秃了顶,太丑了!不能忍,绝对不能忍!!


image.png

我要给Ta添加一个Toolbar

  • 添加Toolbar

修改布局文件,添加Toolbar控件,这里要注意单独使用Toolbar如果不添加背景色默认是无色的。

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/colorPrimary"
        android:minHeight="?attr/actionBarSize" />

效果如图:
image.png
  • 添加带阴影效果的Toolbar

单纯使用Toolbar会发现下方并没有Z轴的阴影效果,想要有阴影效果,就得将Toolbar放入AppBarLayout中,如下:

<android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize" />

    </android.support.design.widget.AppBarLayout>

看一下效果:
image.png
  • 设置Toolbar返回箭头

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            app:navigationIcon="@drawable/ic_arrow_back" />
效果图
  • 调整Toolbar返回箭头左边距

在styles.xml文件里添加下面属性:

    <!--ToolBar返回按钮间距-->
    <style name="ToolbarNavigationButtonStyle" parent="@style/Widget.AppCompat.Toolbar.Button.Navigation">
        <item name="android:minWidth">0dp</item>
        <item name="android:paddingLeft">12dp</item>
        <item name="android:paddingRight">12dp</item>
        <item name="android:scaleType">centerInside</item>
        <item name="android:tint">@android:color/white</item> <!-- 为返回icon着色 -->
    </style>

然后再到AppTheme里引用该主题
image.png

最终效果:
image.png
  • 添加Toolbar标题

image.png

效果:
image.png
  • 更改标题字体颜色

styles.xml文件新建style

    <!--Toolbar标题样式-->
    <style name="ToolbarTitleStyle" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">18sp</item>
        <item name="android:textStyle">bold</item>
        <item name="android:gravity">center</item>
    </style>

    <!--Toolbar子标题样式-->
    <style name="ToolbarSubTitleStyle" parent="TextAppearance.Widget.AppCompat.Toolbar.Subtitle">
        <item name="android:textColor">@android:color/white</item>
        <item name="android:textSize">14sp</item>
        <item name="android:textStyle">normal</item>
        <item name="android:gravity">center</item>
    </style>

在toolbar布局属性里添加
image.png

效果
image.png
  • 设置Toolbar标题左边距

用到的属性:contentInsetStartWithNavigation
可在布局文件添加:app:contentInsetStartWithNavigation="0dp"
亦可在styles.xml文件配置:

    <!--Toolbar样式总入口-->
    <style name="ToolbarStyle" parent="Widget.AppCompat.Toolbar">
        <item name="contentInsetStartWithNavigation">0dp</item> <!--设置标题距返回按钮间距-->
    </style>

然后:
image.png

效果:
image.png

其实这个0dp只是一个相对值,它有一个默认最小值,经过我的测试,在52以下,随便设置多少,它都是显示的最小值,大于52则逐渐增加(实际不会谁设计间距这么大,顶多是居中罢了)

  • 设置Toolbar标题剧中

貌似Toolbar并没有直接可以设置标题居中显示的属性及api,又因Toolbar实际是个ViewGroup,故在其内部嵌套一个TextView实现居中显示标题

 <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:minHeight="?attr/actionBarSize"
            app:navigationIcon="@drawable/ic_arrow_back">

            <TextView
                android:id="@+id/tv_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:text="Title"
                android:textAppearance="@style/ToolbarTitleStyle" />
        </android.support.v7.widget.Toolbar>

效果如图:
image.png
  • Toolbar添加menu

在res文件夹下新建menu目录,在该目录内新建menu文件

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/action_search"
        android:icon="@drawable/ic_search"
        android:title="Search"
        app:showAsAction="always" />

    <item
        android:id="@+id/action_add"
        android:orderInCategory="101"
        android:title="添加"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_del"
        android:orderInCategory="102"
        android:title="删除"
        app:showAsAction="never" />

    <item
        android:id="@+id/action_share"
        android:orderInCategory="100"
        android:title="分享"
        app:showAsAction="never" />

</menu>

在Activity中重写以下方法加载menu文件

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_do_actions, menu);
        return super.onCreateOptionsMenu(menu);
    }

如果运行无效果,请确保是否初始化Toolbar

        Toolbar toolbar = findViewById(R.id.toolbar);
        toolbar.setTitle("");
        setSupportActionBar(toolbar);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });

效果如图:
image.png

啧啧啧,黑黢黢的,真TM丑。。。

  • Toolbar中menu图标&样式修改

或许将menu中的图标或者是文字变成白色会好看些吧

方法一:

将menu中文字变成白色,在app主题中加入如下属性:
image.png

如图:
image.png

将右边三点变成白色,同样在主题中加入一条属性:
image.png

如图:
image.png
方法二:

通过配置Toolbar主题改变图标文字颜色
在布局文件中加入属性:android:theme="@style/ToolbarTheme"
在styles.xml文件新建style

    <!--Toolbar主题配置-->
    <style name="ToolbarTheme" parent="@style/ThemeOverlay.AppCompat.ActionBar">
        <item name="android:textSize">16sp</item> <!-- menu字号 -->
        <item name="android:textStyle">bold</item><!-- menu粗体 -->
        <item name="actionMenuTextColor">@android:color/white</item> <!-- menu字体颜色,不要加android前缀,否则4.4以前无效 -->
        <item name="android:textColorPrimary">@android:color/holo_red_light</item> <!-- 改变menu图标及隐藏菜单字体颜色 -->
    </style>

此方法会改变menu中图标和never属性菜单的字体颜色:
overflowmenu.gif
  • Toolbar中放入SearchView

在menu菜单中加入:

    <item
        android:id="@+id/action_search"
        android:title="搜索"
        app:showAsAction="always"
        app:actionViewClass="android.support.v7.widget.SearchView" />

再将ToolbarTheme里面这条属性修改为白色
<item name="android:textColorPrimary">@android:color/white</item>
效果貌似还不错:

GIF.gif

  • 修改SearchView的hint文字和颜色

首先要得到SearchView,再调用api设置

    private SearchView mSearchView;
    private SearchView.SearchAutoComplete mSearchAutoComplete;

        @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_do_actions, menu);
        MenuItem searchItem = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) searchItem.getActionView();
        mSearchAutoComplete = mSearchView.findViewById(R.id.search_src_text);
//        mSearchView.setIconified(false); //默认打开搜索框
        //设置Hint文字颜色
        mSearchAutoComplete.setHintTextColor(ContextCompat.getColor(this,android.R.color.darker_gray));
        //设置输入文字颜色
        mSearchAutoComplete.setTextColor(ContextCompat.getColor(this,android.R.color.white));
        //设置Hint文字
        mSearchView.setQueryHint("Hint text here");
        //设置是否显示搜索框展开时的提交按钮
        mSearchView.setSubmitButtonEnabled(false);
        return super.onCreateOptionsMenu(menu);
    }

效果图:
gif001.gif
  • 设置SearchView搜索监听

SearchView输入内容监听

        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                // TODO: 处理一些输入内容改变的逻辑 
                return false;
            }
        });

SearchView关闭按钮监听

        mSearchView.setOnCloseListener(new SearchView.OnCloseListener() {
            @Override
            public boolean onClose() {
                // TODO: 处理一些关闭搜索框后的逻辑,比如还原之前数据 
                return false;
            }
        });

NavigationClickListener关联SearchView,当输入框展开时,点击返回是关闭输入框,否则是关闭当前页面

        toolbar.setNavigationOnClickListener(v -> {
            if (mSearchAutoComplete.isShown()){
                try {
                    //如果展开则先关闭搜索框
                    mSearchAutoComplete.setText("");
                    Method method = mSearchView.getClass().getDeclaredMethod("onCloseClicked");
                    method.setAccessible(true);
                    method.invoke(mSearchView);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }else{
                finish();
            }
        });

效果图:
gif002.gif

如有不完善或者错误之处,希望多多指正。

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

推荐阅读更多精彩内容