臨近年末,項(xiàng)目沒什么新需求了,主要做一些code review和代碼重構(gòu)的工作。有一個(gè)工作是將我們app中的TitleBar替換為Android的原生控件ToolBar,ToolBar出來這么久,相信大家都不會(huì)陌生了。替換的工作并不難,但因?yàn)槲覀傾pp原來的TitleBar是一個(gè)相對(duì)布局中間放了一些ImageButton和TextView等控件組成的,并不符合ToolBar的原生風(fēng)格,所以我一開始打算放棄替換,但經(jīng)過一番Google,發(fā)現(xiàn)原來還是可以輕松實(shí)現(xiàn)的,不得不感嘆ToolBar的定制性真得很強(qiáng)。





關(guān)于ToolBar的基本用法網(wǎng)上一大堆,不會(huì)的童鞋可以自己去Google,我這里簡(jiǎn)單總結(jié)一下如何更自由的定制ToolBar。
一. Title居中
ToolBar默認(rèn)的主Title是居左的,但是我們可以通過自定義ToolBar的子View來達(dá)到顯示居中Title的效果。
<android.support.v7.widget.Toolbar
android:id="@+id/toolBar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="自定義標(biāo)題"
android:textColor="@color/black"
android:textSize="@dimen/title_center_textsize" />
</android.support.v7.widget.Toolbar>
這樣還可以單獨(dú)控制中間標(biāo)題的字體顏色和大小等。使用TextView作為title后,toolbar.setTitle(...)就可以設(shè)置為空或者不用設(shè)置了。
二. 在ToolBar左側(cè)放置Menu
在ToolBar添加Menu時(shí),默認(rèn)都是出現(xiàn)在右側(cè)的,但我的需求是在左側(cè)放置兩個(gè)Menu,本來想通過設(shè)置NavigationIcon和logo來解決,但如果這樣,只能設(shè)置兩個(gè)圖標(biāo)在左邊,而且圖標(biāo)之間的間距沒辦法調(diào)整,所以靈活性很差。后來發(fā)現(xiàn)一個(gè)非常好用的控件ActionMenuView,以前它可以搭配ActionBar來使用,現(xiàn)在同樣可以用來自定義ToolBar的菜單。
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/title_height"
android:background="@color/title_background"
android:minHeight="@dimen/title_height"
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<android.support.v7.widget.ActionMenuView
android:id="@+id/action_menu_view"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<TextView
android:id="@+id/toolbar_title"
style="@style/TitleBar.Text.Center"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
</android.support.v7.widget.Toolbar>
將ActionMenuView放在ToolBar子布局中的第一個(gè),它就會(huì)繪制在左側(cè),還需要注意給ToolBar設(shè)置下面的屬性(而且需要注意,這里要使用"app:xxx"而不是"Android:xxx",否則會(huì)有兼容性問題),因?yàn)楫?dāng)沒有設(shè)置NavigationIcon和logo時(shí),ToolBar左側(cè)默認(rèn)有一小段空白:
app:contentInsetLeft="0dp"
app:contentInsetStart="0dp"
然后我們需要給ActionMenuView加載菜單,代碼很簡(jiǎn)單:
ActionMenuView actionMenuView = (ActionMenuView) toolbar.findViewById(R.id.action_menu_view);
getMenuInflater().inflate(R.menu.menu_toolbar_left, actionMenuView.getMenu());
// 點(diǎn)擊事件
actionMenuView.setOnMenuItemClickListener(new ActionMenuView.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return false;
}
});
R.menu.menu_toolbar_left.xml文件就是放置在menu文件夾下我們自定義的菜單資源文件。
<?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/left_back_btn"
android:icon="@drawable/ic_titlebar_back"
android:title="后退"
app:showAsAction="always"/>
<item
android:id="@+id/left_text_btn"
android:title=""
app:actionLayout="@layout/menu_layout_text_btn"
app:showAsAction="always"/>
<item
android:id="@+id/left_icon_btn"
android:icon="@drawable/ic_launcher"
android:title=""
app:showAsAction="always"/>
</menu>

細(xì)心的同學(xué)應(yīng)該看到我第二個(gè)id為left_text_btn的菜單使用了app:actionLayout屬性,這是使當(dāng)前菜單顯示你指定的layout布局,也是非常方便的定制功能。因?yàn)門oolBar中所有菜單的顏色必須統(tǒng)一指定(通過在AppTheme中指定"android:actionMenuTextColor"屬性),沒辦法分開設(shè)置,所以如果需要單獨(dú)設(shè)置某個(gè)菜單的顏色,可以指定它的app:actionLayout,上面的"@layout/menu_layout_text_btn"布局為一個(gè)簡(jiǎn)單的TextView,就不貼了,也可以通過代碼指定:
MenuItem menuItem = actionMenuView.getMenu().findItem(R.id.left_text_btn);
menuItem.setActionView(R.layout.menu_layout_text_btn);
還有一個(gè)細(xì)節(jié)可能也有人關(guān)注到,就是如果菜單按鈕是通過icon屬性設(shè)置的圖標(biāo)按鈕,長(zhǎng)按就會(huì)出現(xiàn)Toast文字(title屬性設(shè)置的文字)提示這個(gè)圖標(biāo)按鈕的作用,即便title設(shè)為空字符串,也還是會(huì)彈出Toast,這是Android系統(tǒng)的默認(rèn)設(shè)置,無法取消,如果實(shí)在不想要這個(gè)提示,可以通過指定其app:actionLayout為一個(gè)自定義的ImageButton來實(shí)現(xiàn)。注意當(dāng)使用app:actionLayout屬性定制菜單時(shí),點(diǎn)擊事件就需要通過設(shè)置app:actionLayout指定的layout中的View的Click監(jiān)聽來實(shí)現(xiàn)了
// 此時(shí)menuItem.getActionView()獲取的View就是自定義的ImageButton或TextView
menuItem.getActionView().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
默認(rèn)的MenuItem點(diǎn)擊效果為一個(gè)小圓形的水波紋效果,查看自帶style是通過下面的資源文件實(shí)現(xiàn)的,自定義時(shí)可以指定為它以保持點(diǎn)擊效果一致:
android:background="?attr/actionBarItemBackground"
三. Menu的間距和文字屬性設(shè)置
有時(shí)我們需要設(shè)置按鈕文字的顏色以及大小,還需要調(diào)整相鄰按鈕之間的間距,比如上圖中可能有人會(huì)覺得"<"后退按鈕和“關(guān)閉”按鈕之間的間距太大了,這要如何調(diào)整呢?都可以通過指定Theme中的屬性來設(shè)置。
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:actionMenuTextColor">@color/primary</item>
<item name="android:actionMenuTextAppearance">@style/ActionMenuTextAppearance</item>
<item name="android:actionButtonStyle">@style/ActionButtonStyle</item>
</style>
android:actionMenuTextColor屬性用來指定菜單文字的顏色,android:actionMenuTextAppearance是用來指定菜單文字的大小等屬性
<style name="ActionMenuTextAppearance" parent="@android:style/TextAppearance.Holo.Widget.ActionBar.Menu">
<item name="android:textSize">@dimen/title_right_textsize</item>
<item name="android:textStyle">normal</item>
</style>
android:actionButtonStyle可以修改按鈕的大小和間距
<style name="ActionButtonStyle" parent="Widget.AppCompat.Light.ActionButton">
<item name="android:minWidth">44dp</item>
<item name="android:paddingLeft">10dp</item>
<item name="android:paddingRight">10dp</item>
</style>
這里因?yàn)閍pi17以下使用的是paddingLeft和paddingRight,而api17以上使用的是paddingStart和paddingEnd(通過查看Widget.AppCompat.Light.ActionButton的style源碼也可以看到),所以這里需要新建values-v17文件夾,在其下新建styles.xml來專門指定api17以上的ActionButtonStyle:
<style name="ActionButtonStyle" parent="Widget.AppCompat.Light.ActionButton">
<item name="android:minWidth">44dp</item>
<item name="android:paddingStart">10dp</item>
<item name="android:paddingEnd">10dp</item>
</style>
ActionButton默認(rèn)的android:minWidth屬性值為48dp,默認(rèn)左右的padding值為12dp。

所以如果我們需要修改按鈕的間距,可以修改以上三個(gè)屬性值,改小之后可以明顯看到間距減小

四. 總結(jié)
以上就是這次替換的一小點(diǎn)經(jīng)驗(yàn)總結(jié),右邊的菜單通過直接給ToolBar添加Menu就可以了,當(dāng)然你也可以通過自定義的方式實(shí)現(xiàn)。通過以上幾點(diǎn),我們可以看到ToolBar的非常靈活的可定制性,不僅如此,如果你的菜單還有更不一樣的地方,可以把ToolBar中的內(nèi)容全部通過自定義布局來實(shí)現(xiàn),也就是全部通過ToolBar的子View們來展示ToolBar的內(nèi)容。