寫在前面
•前言
這兩天,學完了 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】
【Android開發:最詳細的 Toolbar 開發實踐總結】
在此感謝!