Android 之 ToolBar 踩坑筆記


 

寫在前面

•前言

  這兩天,學完了 Fragment 的基礎知識,正准備跟着《第一行代碼》學習制作一個簡易版的新聞應用;

  嘀嘀嘀~~~

  一聲消息傳來,像往常一樣,打開 QQ,當我看到 QQ 界面的時候:

    

  突發奇想,我是不是可以嘗試制作一下這個界面,以及完成一些點擊跳轉的效果;

  說干就干,先大致畫了個草圖,明確該如何分配空間:

    

  忍不住叨叨兩句,畫這種嵌套的方形框, Notability 真香;

  大體理了理思路:

  • 將 ipad 界面一分為二,左邊是一個權重為 1 的 LinearLayout 
  • 右邊是一個權重為 2 的 LinearLayout

  當點擊左邊消息列表時,右邊動態添加一個 Fragment,思路是不是還蠻清晰的~~~

  左右分工好后,接着開始細究左邊內部的分工了;

  我將左邊的 LinearLayout 分成了三塊,就暫且叫他們 a,b,c;

  在設計 a 的時候,也就是這一塊:

    

  最左邊的頭像我用 ImageView 控件體現,中間的,暫且用 TextView 控件實現;

  最右邊的 ➕ 有一個彈出菜單,當然選擇 menu 來實現嘍;

  當開始敲 menu 控件的時候,突然發現,我好像沒怎么深入的學習過,so,一場惡補開始了;

  翻閱了各種各樣的博客,終於,完成了這篇驚世之作——在活動中使用 menu

  可是,我卻翻車了,怎么也實現不了QQ里的這種效果;

  不放棄的我又去找度娘聊天去了,還好找到了一篇,快點我

  ToolBar 是什么玩意????

  沒辦法,接着肝;

  苦熬一上午,終於肝明白了,以此記錄;

  接下來要步入正題嘍~~~~~

•簡介

  Toolbar 是在 Android 5.0 開始推出的一個 Material Design 風格的導航控件 ;

  Google 非常推薦大家使用 Toolbar 來作為Android客戶端的導航欄,以此來取代之前的 Actionbar 。

  與 Actionbar 相比,Toolbar 明顯要靈活的多。

  它不像 Actionbar 一樣,一定要固定在Activity的頂部,而是可以放到界面的任意位置。

  除此之外,在設計 Toolbar 的時候,Google也留給了開發者很多可定制修改的余地;

  這些可定制修改的屬性在API文檔中都有詳細介紹,如:

  • 設置導航欄圖標;
  • 設置App的logo;
  • 支持設置標題和子標題;
  • 支持添加一個或多個的自定義控件;
  • 支持Action Menu;

•准備工作

  首先,新建一個項目,選擇 Empty Activity 這個選項,並命名為 Tool Bar;

  進入 Project 模式,點擊 app/src/main/,找到 AndroidManifest.xml 文件;

  找到這句話  android:theme="@style/Theme.ToolBar"> ;

  可以看到,這里使用  android:theme  屬性指定了一個 Theme.TestToolBar 的主提。

  那么,這個 Theme.TestToolBar 又是在哪里定義的呢?

  按住 ctrl,鼠標點擊  "@style/Theme.ToolBar">  這句話:

    

  通過快捷鍵 ctrl,Android Studio 引領我們找到了這句話的出處;

  在我這里,這個文件在 themes.xml 中:

    

  而並不是在 res/values/styles.xml 中,《第一行代碼》以及好多優質博客都聲明在 styles.xml 文件中;

  這是為什么呢?

  來看這句話  <style name="Theme.ToolBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> ;

  這里定義了一個叫 Theme.TestToolBar 的主題;

  然后指定它的 parent 主題是  "Theme.MaterialComponents.DayNight.DarkActionBar" 。

  這個 DarkActionBar 是一個深色的 ActionBar 主題;

  而我們現在准備使用 ToolBar 來替代 ActionBar,因此需要指定一個不帶 ActionBar 的主題;

  通常有  "Theme.AppCompat.NoActionBar"  和  "Theme.AppCompat.Light.NoActionBar"  這兩種主題可選。

  其中前者表示深色主題,它會將界面的主題顏色設成深色,陪襯顏色設成淡色;

  而后者表示淡色主題,它會將界面的主題顏色設成淡色,陪襯顏色設成深色;

  具體效果,上手便知,這里我們選擇后者;

  更改 parent 屬性為后者:

     <style name="Theme.ToolBar" parent="Theme.AppCompat.Light.NoActionBar"> 

  至於其他的:

    

  暫且不管它們,你可以留着,或者刪了也行,這不是本次的重點!!!

  如果你嫌上邊的配置過於繁瑣,那么恭喜你,接下來本博主將帶着你用一行代碼簡單粗暴的實現上述效果;

  是不是挺期待的;

  在 MainActivity.java 中加入這一行代碼  supportRequestWindowFeature(Window.FEATURE_NO_TITLE); ;

  注意,一定要放在  setContentView()  之前,不然,會出錯;

  

注意

  我的 MainActivity 是繼承了 AppCompatActivity的;

  如果是繼承 Activity 就應該調用  requestWindowFeature(Window.FEATURE_NO_TITLE); ;

  是不是只通過一行代碼就簡單粗暴的實現了上述繁瑣的配置。

  現在,我們已經將 ActionBar 隱藏起來了,那么,接下來看一看如何使用 ToolBar 來替代 ActionBar。

 


Toolbar的簡單用法

•初次使用 Toolbar

  介紹步驟之前,請允許我把本次內容將要使用的圖標一一列舉出來;

        

  至於這些圖標的命名問題,我相信,屏幕前聰明的你會從代碼中找到蛛絲馬跡的,哈哈哈~~~~

  修改 activity_main.xml 中的代碼;

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <!--        設置成黃色的背景色-->
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/yello"
        />

</LinearLayout>

  有關這個 Toolbar 的使用,《第一行代碼》以及一些優質博客,用的都是  <android.support.v7.widget.Toolbar ;

  我也嘗試着用,然后又是一頓瞎搗鼓,也沒搗鼓出啥花來;

   萬般無奈,搜了搜包方面的博客,找到了這篇,Android AndroidX的遷移

  

  大概是說,過年的時候,Android 也會換身新衣服穿;

  所以,我們安心用 androidx 中的 Toolbar 就行,沒必要非得去實現  <android.support.v7.widget.Toolbar ;

——來自萌新的見解,大佬輕點噴

  好了,這里的廢話暫且說這么多,下面步入正題;

  接着修改 MainActivity.java 中的代碼;

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

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

}

  這里需要注意一點,再導入 Toolbar 包的時候,有兩個選擇:

    

  我選擇了第一個  import androidx.appcompat.widget.Toolbar; ;

  因為如果選擇第二個的話,語句  setSupportActionBar(toolbar);  就會報錯,我也不知道為什么;

運行效果

  

•Title and SubTitle

  接下來,我們為 Toolbar 設置標題、子標題,並設置標題子標題顏色;

  修改 activity_main.xml 中的代碼;

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="horizontal">

    <!--        設置成黃色的背景色-->
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/yello"
        app:title="title"
        app:titleTextColor="@color/black"
        app:subtitle="sub title"
        app:subtitleTextColor="@color/white"
        />

</LinearLayout>

  乍一看,僅僅是在 Toolbar 中加入了  app:title , app:titleTextColor , app:subtitle , app:subtitleTextColor  這四句話;

  其實,還額外加入了  xmlns:app="http://schemas.android.com/apk/res-auto" ,也就是第 3 行語句;

  這里使用  xmlns:app  指定了一個自定義屬性的命名空間,當然,你也可以將  app  換成你想要的其他命名。

  思考一下,正是由於每個布局文件都會使用  xmlns:android 來指定一個命名空間;

  因此,我們才一只能用  android:id , android:layout_width 等寫法;

  那么,這里指定了  xmlns:app ,也就是說,現在可以使用  app:attribute  這樣的寫法了。

  但是為什么這里要指定一個新的命名空間呢?

  目的是為了能夠兼容之前的老系統,具體詳情自行百度,這里不再贅述。

運行效果

  

•左側導航欄

  修改 MainActivity.java 代碼;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

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

        getSupportActionBar().setHomeButtonEnabled(true); //設置導航欄可用
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        //為導航欄設置點擊事件
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,"back",Toast.LENGTH_SHORT).show();
            }
        });
    }
}

  並通過  toolbar.setNavigationOnClickListener() 為其設置點擊事件;

運行效果

  

•右側溢出菜單

  接下來,我們把右側溢出菜單搞出來;

  首先在 res 的 menu 目錄下創建一個 main 資源文件,具體做法參考我的這篇博客

main.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/option_normal_1"
        android:icon="@mipmap/icon_one"
        android:title="普通菜單1"
        app:showAsAction="ifRoom"/>

    <item android:id="@+id/option_normal_2"
        android:icon="@mipmap/icon_two"
        android:title="普通菜單2"
        app:showAsAction="always"/>

    <item android:id="@+id/option_normal_3"
        android:icon="@mipmap/icon_three"
        android:title="普通菜單3"
        app:showAsAction="withText|always"/>

    <item android:id="@+id/option_normal_4"
        android:title="普通菜單4"
        android:icon="@mipmap/icon_four"
        app:showAsAction="never"/>
</menu>

  修改 MainActivity.java 中的代碼;

public class MainActivity extends AppCompatActivity {

    private Toolbar toolbar;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

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

        getSupportActionBar().setHomeButtonEnabled(true); //設置導航欄可用
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        //為導航欄設置點擊事件
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this,"back",Toast.LENGTH_SHORT).show();
            }
        });

        toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Toast toast = null;
                switch(item.getItemId()){
                    case R.id.option_normal_1:
                        toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
                        break;
                    case R.id.option_normal_2:
                        toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
                        break;
                    case R.id.option_normal_3:
                        toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
                        break;
                    case R.id.option_normal_4:
                        toast = Toast.makeText(MainActivity.this,item.getTitle(), Toast.LENGTH_SHORT);
                        break;
                    default:
                }
                toast.show();
                return true;
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {//為toolbar設置溢出菜單
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main,menu);
        return true;
    }
}

  通過  onCreateOptionsMenu() 方法為 toolbar 設置溢出菜單;

  並通過  setOnMenuItemClickListener() 設置溢出菜單的點擊效果;

運行效果

  

注意

  Toolbar中的 action 按鈕只會顯示圖標,菜單中的 action 按鈕只會顯示文字。

  那如果設置了 ifRoom 屬性之后,既然只顯示圖標不顯示文字,那還設置  android:title=””  文字干嘛呢?

  如果你設置了之后,雖然不顯示,但是你長按相應按鈕后,就會吐司相應文字內容的。

  不信的話,你自己試試;

  還有,有關 app:showAsAction 屬性,已經在 menu 中做過詳細講解,這里就不在贅述;

•Logo

  我們在 activity_main.xml 中通過  app:logo 屬性為 Toolbar 設置 Logo;

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="horizontal">

    <!--        設置成黃色的背景色-->
    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/yello"
        app:title="title"
        app:titleTextColor="@color/black"
        app:subtitle="sub title"
        app:subtitleTextColor="@color/white"
        app:logo="@mipmap/icon_one"
        />

</LinearLayout>

  這里我直接使用了 icon_one,懶得在下載其他圖標了,哈哈哈;

運行效果

  

注意

  NavigationIcon 和 Logo 不建議同時使用,不然 logo 和 title,subtitle的 間距會顯得比較小;

  到此,Toolbar 的所有元素組件都搞出來了,接下來我們接着說如何自定義 Toolbar;

 


自定義Toolbar

•聲明

  因為接下來的內容並沒有 Logo 參與,所以我將這個屬性去掉了;

•自定義導航欄的icon

  只需要在 activity_main.xml 中設置  app:navigationIcon="@mipmap/icon_two" 即可。

  這里我直接使用了 inon_two 圖標;

運行效果

  

•設置溢出菜單icon的顏色

  還記得我們在前面繁瑣配置中的  <style name="Theme.ToolBar" 嗎?

  一定要找到這個文件,因為,一會還會用到,哈哈哈~~~

  將下面這個代碼添加到  <style name="Theme.ToolBar" 中;

<!--設置溢出菜單圖片顏色為紅色-->
<item name="colorControlNormal">@color/red</item>

  注意,這里用的是 @color/red,是我在 res/values 下的 color.xml 文件夾中自定義的顏色;

  不要使用  @android:color/red ,編譯報錯;

運行效果

  

•設置標題和子標題的字體大小

  點擊 app/src/main/res/,找到 values 文件夾,右擊 New->Values Resource File;

  

  新建一個名為 styles 的 xml 文件;

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- toolbar標題文字大小 -->
    <style name="ToolbarTitleSize" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textSize">25sp</item>
    </style>
    <!-- toolbar子標題文字大小 -->
    <style name="ToolbarSubTitleSize" parent="@style/TextAppearance.Widget.AppCompat.Toolbar.Title">
        <item name="android:textSize">12sp</item>
    </style>

</resources>

  並在 activity_main.xml 設置:

app:subtitleTextAppearance="@style/ToolbarSubTitleSize"
app:titleTextAppearance="@style/ToolbarTitleSize"

運行效果

  

•溢出菜單自定義

  首先,將下面這些代碼添加到 styles.xml 中;

    <!-- toolbar溢出菜單圖標自定義 -->
    <style name="OverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow">
        <item name="android:src">@mipmap/icon_add</item>
        <item name="android:scaleType">centerInside</item>
    </style>

  注意,溢出菜單圖標自定義  <style name="OverflowButtonStyle" parent="Widget.AppCompat.ActionButton.Overflow"> ;

  parent 是  "Widget.AppCompat.ActionButton.Overflow" 而不是  "android:Widget.ActionButton.Overflow" 

  如果 parent 屬性設置為后者,那么,Toolbar 並不會成功顯示你定義的圖標;

  因為這個原因,可苦了我了,搜了是好幾個博客,都沒有解決;

  最后還是在 Stack Overflow 的評論中找到了答案;

  接着,將下面的代碼添加到  <style name="Theme.ToolBar" 中;

        <!-- 溢出菜單圖標自定義-->
        <item name="actionOverflowButtonStyle">@style/OverflowButtonStyle</item>

運行結果

  

  溢出菜單的圖標是不是變成 ➕ 了,神奇吧。

•設置溢出菜單彈出位置以及背景顏色,文字顏色

  上邊的效果圖看着很別扭,溢出菜單彈出的位置遮住了 Toolbar;

  所以,我們將溢出菜單彈出位置設置到Toolbar下面;

  在 styles.xml 中添加如下代碼;

    <!--設置溢出菜單彈出位置-->
    <style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow">
        <!-- 是否覆蓋錨點,默認為true,即蓋住Toolbar -->
        <item name="overlapAnchor">false</item>
        <!-- 設置彈出菜單文字顏色 -->
        <item name="android:textColor">@color/white</item>
        <!-- 彈出層背景顏色 -->
        <item name="android:colorBackground">@color/green</item>
    </style>

  並將  <style name="OverflowMenuStyle" parent="@style/Widget.AppCompat.PopupMenu.Overflow"> 屬性引用到 activity_main.xml 中的 Toolbar 中:

     app:popupTheme="@style/OverflowMenuStyle" 

運行結果

  

 

  說好的綠色背景呢???

 

   經過我一番瞎搗鼓,終於整出來了;

  還是得將  <style name="Theme.ToolBar" parent="Theme.MaterialComponents.DayNight.DarkActionBar">  中的 parent 改為:

     parent="Theme.AppCompat.Light.NoActionBar" ;

  那我直接用這個方法不就好了嗎,何必添加  supportRequestWindowFeature(Window.FEATURE_NO_TITLE); 。

 

運行結果

  

 

  最后再叨叨幾句,當前這個版本,是我改版后的;

  其實一開始我寫這篇博客的時候,並不知道  supportRequestWindowFeature(Window.FEATURE_NO_TITLE) ;

  是我在今天(2021.2.8)隨意翻閱博客的時候看到的;

  本着追根究底的態度,我試了試,實現了和修改 themes 同樣的效果;

  最主要的是,添加這個語句,可以使用   toolbar.inflateMenu(R.menu.main); 語句。

 


寫在最后

•結語

  至此,Toolbar 的學習就告一段落了,帶着滿滿的疲憊結束了 Toolbar 的學習;

  最后,奉上我在學習 Toolbar 過程中翻閱過的資料;

  【Android Toolbar詳解——簡書】

  【Android ToolBar詳解——CSDN】

  【Toolbar的詳細介紹和自定義Toolbar

  【Android開發:最詳細的 Toolbar 開發實踐總結

  在此感謝!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM