概述
繼承關係:
java.lang.Object
↳ android.view.View
↳ android.view.ViewGroup
↳ android.widget.Toolbar
複製程式碼
其實toolbar就是一個封裝好的ViewGroup,其主要五大部分對應的子View如下:
//選單,ActionMenuView也是個ViewGroup
private ActionMenuView mMenuView;
//主標題
private TextView mTitleTextView;
//副標題
private TextView mSubtitleTextView;
//導航按鈕
private ImageButton mNavButtonView;
//Logo圖示
private ImageView mLogoView;
複製程式碼
看下圖,比較清晰:
專案封裝
配置theme
為了適配5.0之後安卓的設計,做起statusbar的顏色適配
<style name="AppTheme" parent="Theme.AppCompat.Light.Theme.AppCompat.Light.NoActionBar">
<item name="colorPrimaryDark">@color/main_dark</item>
<item name="colorPrimary">@color/main</item>
<item name="colorAccent">@color/strong</item>
<item name="android:textColorPrimary">@android:color/white</item>
<item name="android:actionBarSize">@dimen/nav_bar_height</item>
</style>
複製程式碼
這裡注意下,主題使用的parent是Theme.AppCompat.Light.NoActionBar
,當然有些專案中配全域性Theme時候還是用的Theme.AppCompat.Light.DarkActionBar
,這時候需要改成沒有ActionBar的主題,這裡可以直接改成Theme.AppCompat.Light.NoActionBar
,但是有些專案裡如果想有些地方使用Actionbar有些地方使用Toolbar(當然很少。。)可以這樣配一下即可:
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
複製程式碼
然後在需要使用Toolbar的activity裡給他配上這樣的theme即可:
<activity
android:name=".ui.activity.MainTabBarActivity"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:launchMode="singleTask"
android:theme="@style/AppTheme.NoActionBar"
android:windowSoftInputMode="stateHidden">
</activity>
複製程式碼
關於theme中幾個color欄位的描述看谷歌官方圖,如下:
或者看谷歌文件(自備梯子):Material Theme
由於我們專案裡設定了toobar的高度,這裡指定了actionBarSize,然後通過設定toolbar高度為這個值;
佈局程式碼
由於專案中toolbar歸屬於fragment管理,所以這裡是將toolbar封裝在fragment中處理了,這裡通過各個fragment的xml新增<include layout="@layout/toolbar_layout"/>
toolbar_layout.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="1dp">
<TextView
android:id="@+id/nav_left_text"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:drawableLeft="@drawable/nav_back_light"
android:drawableStart="@drawable/nav_back_light"
android:layout_gravity = "start"
android:gravity="center"
android:minWidth="50dp"
android:text="返回"
android:textColor="@android:color/white"
android:textSize="@dimen/font_title"
android:visibility="gone"/>
<TextView
android:id="@+id/center_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity = "center"
android:textColor="@android:color/white"
android:textSize="@dimen/font_large"
tools:text="標題" />
<TextView
android:id="@+id/nav_right_text_button"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity = "end"
android:gravity="center"
android:minWidth="50dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:textColor="@color/color_999"
android:textSize="@dimen/font_normal"
android:visibility="gone" />
</android.support.v7.widget.Toolbar>
複製程式碼
toolbar上的東西被我分成五種:
- navigationicon:通過.setNavigationIcon去處理
- logo:通過setlogo
- title與subtitle:通過.setTitle與setSubtitle去處理
- 自定義部分:這裡也分成左中右三個部分,可以看上面佈局檔案,通過標籤
android:layout_gravity
來指定位置,這裡有坑,自定義部分佈局最左邊有間隙,如果要去掉,可以設定:contentInset
這個標籤去除。 - menu:menu的顯示方式可以自行設定
這樣來看,基本所有的需求都能滿足了;
fragment中抽象封裝:
這裡要看各個專案需求,由於我們公司專案中對最右邊圖示靈活度要求並不高,我一般使用menu就可以解決了,如果menu不能滿足你,完全可以使用自定義部分中的“右部分”。
下面進入封裝,在baseFragment中做了如下封裝,專案中使用的是JakeWharton的注入框架butterknife連結
- 首先注入toolbar及自定義部分中除最右邊圖示的控制元件,因為最右邊圖示我們專案中一般menu就夠用了:
@BindView(R.id.toolbar)
protected Toolbar mToolBar;
@BindView(R.id.center_title)
TextView mCenterTitle;
@BindView(R.id.nav_left_text)
TextView mNavLeftText;
複製程式碼
- 然後在初始化fragment檢視時候將mToolBar、mCenterTitle、mNavLeftText傳給其子fragment進行定製,這三個控制元件傳遞出去後完全可以定製navigationicon、logo、title與subtitle、自定義部分這四個部分。以下程式碼中的initview和popFragment是我封裝好的在fragment的OncreateView時候呼叫的,詳細封裝請看:淺談Activity,Fragment模組化封裝
@Override
protected void initView(View view, Bundle savedInstanceState) {
initToolBar(mToolBar, mCenterTitle, mNavLeftText);
}
複製程式碼
protected void initToolBar(Toolbar toolbar, TextView centerTitle, TextView navLeftText){
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false);
toolbar.setNavigationIcon(R.drawable.nav_back_light);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popFragment();
}
});
}
複製程式碼
這裡有個坑:
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayShowTitleEnabled(false);
複製程式碼
必須設定這個,不然預設的title一直在,即使你設定了toolbar.settitle("xxoo")。。。
這裡做了一件事,給navigationButton導航按鈕做了個監聽,pop出當前這個fragment出棧
- 還剩最後一個東西沒有定製:menu
這個很簡單,不過也要注意下,必須在fragment中設定選單,一定要先設定:
setHasOptionsMenu(true);
複製程式碼
關於原始碼,可以去看下,然後處理方式很簡單了:
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.search, menu);
super.onCreateOptionsMenu(menu, inflater);
}
複製程式碼
這裡也有個坑:如果你沒有設定:
((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
複製程式碼
那麼onCreateOptionsMenu
並不會被回撥。
- 最後做下menu的監聽即可:
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
}
return true;
}
});
複製程式碼
總結
Toolbar是android5.0之後出現的MD設計風的控制元件,支援5.0之後的elevation特性,相比較Actionbar具有高度自定義的特性,因為其本身是一個ViewGroup內部佈局完全自由處理,這樣大大擴充套件了其自由定製性,不多說,趕緊開始替換Actionbar吧!
具體程式碼請看我的github:Android練習小專案