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

如有不完善或者錯誤之處,希望多多指正。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容