Toolbar使用總結

C_YQ發表於2019-04-20

Toolbar 概述

Toolbar 繼承的是ViewGroup,用來替代原來的ActionBar

Toolbar使用總結

一個Toolbar 從左到右包括了 一個navigation button、一個logo、一個title和subtitle、一個或多個自定義的View和一個 action menu 這5部分

Toolbar使用總結

基本屬性設定

在佈局檔案中設定

  • app:navigationIcon 設定navigation button
  • app:logo 設定logo 圖示
  • app:title 設定標題
  • app:titleTextColor 設定標題文字顏色
  • app:subtitle 設定副標題
  • app:subtitleTextColor 設定副標題文字顏色
  • app:popupTheme Reference to a theme that should be used to inflate popups shown by widgets in the toolbar.
  • app:titleTextAppearance 設定title text 相關屬性,如:字型,顏色,大小等等
  • app:subtitleTextAppearance 設定subtitletext相關屬性,如:字型,顏色,大小等等
  • app:logoDescription logo 描述
  • android:background Toolbar 背景
  • android:theme 主題

在Java中設定

        mToolbar = findViewById(R.id.toolbar);
        mMenuView = findViewById(R.id.toolbar_action_menu);
        mToolbar.setTitle("John");
        mToolbar.setNavigationIcon(R.drawable.ic_menu);
        mToolbar.setNavigationOnClickListener(this::OnBackClick);
        mToolbar.setSubtitle("Sub");
//         設定溢位選單的圖示
//        mToolbar.setOverflowIcon(ContextCompat.getDrawable(getApplicationContext(),R.drawable.menu));
        mToolbar.inflateMenu(R.menu.toolbar_menu);
        mToolbar.setOnMenuItemClickListener(menuItem -> {

            //利用colorFilter動態更改圖示顏色
//            menuItem.getIcon().setColorFilter(Color.parseColor("#223344"),PorterDuff.Mode.MULTIPLY);

            switch (menuItem.getItemId()){
                case R.id.toolbar_call:
                    Toast.makeText(MainActivity.this,"toolbar_call",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.toolbar_delete:
                    Toast.makeText(MainActivity.this,"toolbar_delete",Toast.LENGTH_SHORT).show();
                    break;
                case R.id.toolbar_mail:
                    Toast.makeText(MainActivity.this,"toolbar_mail",Toast.LENGTH_SHORT).show();
                    break;
            }
            return true;
        });
複製程式碼

亦可以通過setSupportActionbar,再呼叫getSupportActionBar,當成actionBar使用,若沒有則,setSupportActionbar,則onCreateOptionsMenu不會回撥

Toolbar 的使用

1、更改Android “AppTheme”,指定為Theme.AppCompat.Light.NoActionBar

    <style name="AppTheme" 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>
        <!--更改menu item間隔-->
        <item name="android:actionButtonStyle">@style/MyActionButtonStyle</item>
    </style>
複製程式碼

MyActionButtonStyle:

 <!--menu item 之間的間隔-->
    <style name="MyActionButtonStyle" parent="Widget.AppCompat.ActionButton">
        <item name="android:minWidth">72dip</item>
    </style>
複製程式碼

2、在佈局檔案中新增Toolbar

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/colorPrimary"
        android:theme="@style/MyToolBarTheme"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:titleTextAppearance="@style/Toolbar.TitleText"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">
    </android.support.v7.widget.Toolbar>
複製程式碼

MyToolbarTheme:

<style name="MyToolBarTheme" parent="ThemeOverlay.AppCompat.Dark.ActionBar">
        <!--更改溢位選單文字顏色-->
        <item name="android:textColor">@color/colorAccent</item>
        <!--更改toolbar選單文字大小,包括溢位選單上的,和顯示上的-->
        <item name="android:textSize">25sp</item>
        <!--更改toolbar上的選單顯示文字顏色-->
        <item name="android:actionMenuTextColor">@color/colorPrimaryDark</item>
        <!-- 設定Menu視窗不覆蓋Toolbar檢視 -->
        <item name="overlapAnchor">false</item>

        <!--設定title與navigationIcon的間隔-->
        <item name="contentInsetStart">0dp</item>
        <item name="contentInsetLeft">0dp</item>
        <item name="contentInsetStartWithNavigation">0dp</item>

    </style>
複製程式碼

Toolbar.TitleText:

<!--Toolbar標題文字大小-->
<style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
    <item name="android:textSize">15sp</item>
</style>
複製程式碼

3、在java中獲取toolbar並設定屬性

Toolbar特殊需求使用

1、 更改溢位選單文字顏色

Toolbar使用總結
指定MyToolbarTheme(如上),新增:

<item name="android:textColor">@color/colorAccent</item>

2、 更改toolbar選單文字大小,包括溢位選單上的,和顯示上的

  • 指定MyToolbarTheme(如上),新增:

<item name="android:textSize">25sp</item>

  • Toolbar標題文字大小

Toolbar使用總結

<!--Toolbar標題文字大小-->
<style name="Toolbar.TitleText" parent="TextAppearance.Widget.AppCompat.Toolbar.Title">
    <item name="android:textSize">15sp</item>
</style>
複製程式碼

3、更改toolbar上的選單顯示文字顏色

Toolbar使用總結
指定MyToolbarTheme(如上),新增: <item name="android:actionMenuTextColor">@color/colorPrimaryDark</item>

4、設定Menu視窗不覆蓋Toolbar檢視

Toolbar使用總結
指定MyToolbarTheme(如上),新增: <item name="overlapAnchor">false</item>

5、設定title與navigationIcon的間隔

Toolbar使用總結
指定MyToolbarTheme(如上),新增:

<item name="contentInsetStart">0dp</item>
<item name="contentInsetLeft">0dp</item>
<item name="contentInsetStartWithNavigation">0dp</item>
複製程式碼

6、設定menu item 之間的間隔

Toolbar使用總結
在“AppTheme”中,新增:

<item name="android:actionButtonStyle">@style/MyActionButtonStyle</item>

MyActionButtonStyle:

    <style name="MyActionButtonStyle" parent="Widget.AppCompat.ActionButton">
        <item name="android:minWidth">72dip</item>
    </style>
複製程式碼

7、標題居中

Toolbar使用總結
在Toolbar裡面放置一個TextView控制元件作為居中的標題來使用,再將Toolbar的Title隱藏起來即可實現Toolbar標題居中的效果

Toolbar使用總結

若有使用setSupportActionBar(),則呼叫getSupportActionBar().setDisplayShowTitleEnabled(false);隱藏標題;若沒設定,只要toolbar不設定title即可

8、讓選單同時顯示圖示和文字

只對setSupportActionBar起作用

    // 讓選單同時顯示圖示和文字
    @SuppressWarnings("PrivateApi")
    @Override
    public boolean onMenuOpened(int featureId, Menu menu) {
        if (menu != null) {
            if (menu.getClass().getSimpleName().equalsIgnoreCase("MenuBuilder")) {
                try {
                    Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    method.setAccessible(true);
                    method.invoke(menu, true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return super.onMenuOpened(featureId, menu);
    }
複製程式碼

ActionMenuView

選單預設在最右邊,使用ActionMenuView可更改選單顯示位置,並可以動態刪除新增選單

Toolbar使用總結

1、在toolbar中增加ActionMenuView

Toolbar使用總結

2、在java中動態載入選單和設定監聽

mMenuView = findViewById(R.id.toolbar_action_menu);
//載入選單
getMenuInflater().inflate(R.menu.toolbar_menu,mMenuView.getMenu());
//設定選單監聽
mMenuView.setOnMenuItemClickListener(menuItem -> {
    switch (menuItem.getItemId()){
        case R.id.toolbar_call:
            Toast.makeText(MainActivity.this,"toolbar_call",Toast.LENGTH_SHORT).show();
            break;
        case R.id.toolbar_delete:
            Toast.makeText(MainActivity.this,"toolbar_delete",Toast.LENGTH_SHORT).show();
            break;
        case R.id.toolbar_mail:
            Toast.makeText(MainActivity.this,"toolbar_mail",Toast.LENGTH_SHORT).show();
            break;
    }
    
    //動態改變選單
    mMenuView.getMenu().clear();
    getMenuInflater().inflate(R.menu.nav_menu,mMenuView.getMenu());
            return true;
        });
複製程式碼

app:actionViewClass

Toolbar使用總結

<item
        android:id="@+id/toolbar_delete"
        android:title="delete"
        android:icon="@drawable/ic_delete"
        android:orderInCategory="100"
        app:actionViewClass="android.widget.Button"
        app:showAsAction="always"/>
複製程式碼

最後在java中獲取物件

    MenuItem item = menu.findItem(R.id.toolbar_delete);
    Button button = (Button) item.getActionView().findViewById(R.id.menu_button);
    button.setOnClickListener(view -> {
        Toast.makeText(MainActivity.this,"Button",Toast.LENGTH_SHORT).show();
   });
複製程式碼

注意: 若呼叫setSupportActionBar,則在onCreateOptionsMenu(Menu menu)中獲取menu引用,否則直接Menu menu = mToolbar.getMenu();

結合searchView

Toolbar 結合SearchView

app:actionLayout

Toolbar使用總結

<item
    android:id="@+id/toolbar_delete"
    android:title="delete"
    android:icon="@drawable/ic_delete"
    android:orderInCategory="100"
    app:actionLayout="@layout/menu_action"
    app:showAsAction="always"/>
複製程式碼

注意:menu_action佈局檔案的內容必須以RelativeLayout作為根容器佈局,否則,actionLayout 對應的檢視寬度不足以填充滿 Toolbar 或者說 ActionBar 的寬度,顯示效果如同設定 layout_width 屬性值為 wrap_content 一般。

Toolbar使用總結

注意:第二,actionLayout 屬性必須使用 app 作為名稱空間,如果使用 android 的話,會導致 menuItem 物件通過 getActionView() 始終獲取的物件為 null 。

最後在java中獲取物件

    MenuItem item = menu.findItem(R.id.toolbar_delete);
    Button button = (Button) item.getActionView().findViewById(R.id.menu_button);
    button.setOnClickListener(view -> {
        Toast.makeText(MainActivity.this,"Button",Toast.LENGTH_SHORT).show();
   });
複製程式碼

注意: 若呼叫setSupportActionBar,則在onCreateOptionsMenu(Menu menu)中獲取menu引用,否則直接Menu menu = mToolbar.getMenu();

Fragment中使用

有時候需要在Fragment中使用Toolbar,比如Activity中不同的Tab顯示不同的Fragment,同時每個Tab的Toolbar標題、Menu均不相同,這時在Activity中使用同一個Toolbar就相當不方便了。我們可以在每個Fragment的佈局中新增各自的Toolbar,然後在Fragment中單獨控制。

與Activity中使用Toolbar有所不同。替換ActionBar時,需要給setSupportActionBar方法新增作用物件:

((AppCompatActivity)getActivity()).setSupportActionBar((Toolbar) mContentView.findViewById(R.id.tb_toolbar));
複製程式碼

新增Options Menu時,需要額外呼叫setHasOptionsMenu(true);方法,確保onCreateOptionsMenu()方法得以呼叫,並且onCreateOptionsMenu()方法多了一個MenuInflater引數:

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
	super.onCreateOptionsMenu(menu, inflater);
	inflater.inflate(R.menu.search, menu);
}
複製程式碼

注意: MenuItem 的點選事件會先執行宿主 Activity 中的 onOptionsItemSelected 方法,然後再將事件傳遞到 Fragment 中。所以,如果需要覆蓋或者說遮蔽 Activity 的影響,需要在宿主 Activity 中修改該方法的返回值為 flase,如:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    ...
    return false;
}
複製程式碼

參考連結

  1. Material Design 之 Toolbar
  2. MaterialDesign 之 SearchView 全面解鎖
  3. Android Toolbar,你想知道的都在這裡了