Toolbar設定掉坑總結

jlanglang發表於2018-01-12

前言:

因為需要封裝toolbar,所以徹底的研究了下toolbar, 以前只是簡單用用,現在發現完全用起來很多坑,總結一下.

先來張效果圖:

QQ圖片20170226164432.png

Toolbar的結構其實很簡單:

1.NavigationIcon 2.Logo 3.Title 4.subTitle 5.menu. 常用的:1,3,5

友情提示:

getSupportActionBar()一定要在setSupportActionBar(Toolbar toolbar)之後呼叫

先說常用的:

1.NavigationIcon的幾個方法

//設定是否新增顯示NavigationIcon.如果要用
void setDisplayHomeAsUpEnabled(boolean showHomeAsUp);
//設定NavigationIcon的icon.可以是Drawable ,也可以是ResId
void setNavigationIcon(@Nullable Drawable icon);
void setNavigationIcon(@DrawableRes int resId) 
//設定NavigationIcon的點選監聽.
void setNavigationOnClickListener(OnClickListener listener);
複製程式碼
具體使用:
Toolbar mToolbar =  (Toolbar)findViewById(R.id.toolbar)
//設定Toolbar
 setSupportActionBar(mToolbar);
//顯示NavigationIcon,這個方法是ActionBar的方法.Toolbar沒有這個方法.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
//設定icon
mToolbar.setNavigationIcon(drawable);
//設定監聽.必須在setSupportActionBar()之後呼叫
mToolbar.setNavigationOnClickListener(clickListener);
複製程式碼
總結幾個坑:

1.必須先 setSupportActionBar(mToolbar).

2.setDisplayHomeAsUpEnabled(true)是ActionBar的方法.

3.setNavigationOnClickListener()必須要在setSupportActionBar()之後呼叫才能生效.因為setSupportActionBar(Toolbar),會將Toolbar轉換成Acitionbar.點選監聽也會重新設定.

2.Title

幾個方法:
//是否顯示
getSupportActionBar().setDisplayShowTitleEnabled(boolean showTitle);
//設定title.
getSupportActionBar().setTitle(title);
//設定title.
Toolbar.setTitle(title);
//設定Margin邊距.
Toolbar.setTitleMargin();
//設定字型.
Toolbar.setTitleTextAppearance();
//設定字的顏色
Toolbar.setTitleTextColor(int color);
複製程式碼
總結:

使用比較簡單.基本看方法名就知道是幹嘛的了.也沒什麼坑. Toolbar直接設定title或者getSupportActionBar()再設定title都可以.

3 Menu選單

這玩意用起來有點蛋疼.坑挺多的.

先說建立:

  @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        //寫一個menu的資原始檔.然後建立就行了.
        getMenuInflater().inflate(R.menu.menu,menu);
        return super.onCreateOptionsMenu(menu);
    }

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto"
      xmlns:tools="http://schemas.android.com/tools"
      tools:context="com.example.acctionbaractivitydemo.MainActivity">
    <item
        android:id="@+id/menu1"
        //圖示
        android:icon="@mipmap/ic_launcher"
        //名字
        android:title=""
        app:showAsAction="withText|ifRoom"/>
    <item
        android:id="@+id/menu2"
        android:icon="@mipmap/ic_launcher"
        android:title="哈哈"
        app:showAsAction="withText"/>
    <item
        android:id="@+id/menu3"
        android:icon="@mipmap/ic_launcher"
        android:title="呵呵"
        app:showAsAction="withText"/>
</menu>

//showAsAction這個屬性的值有: 
//1、always:使選單項一直顯示在ToolBar上。 
//2、ifRoom:如果有足夠的空間,這個值會使選單項顯示在ToolBar上。 
//3、never:使選單項永遠都不出現在ToolBar上,在…的子項中顯示。 
//4、withText:使選單項和它的圖示,選單文字一起顯示。
複製程式碼

設定Menu點選

  /**
     * 選單項被點選時呼叫,也就是選單項的監聽方法。
     * 通過這幾個方法,可以得知,對於Activity,同一時間只能顯示和監聽一個Menu 物件.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        return super.onOptionsItemSelected(item);
    }
   //通過設定toolbar進行監聽,在setSupportActionBar(Toolbar toolbar)之前設定可能會失 效.
    Toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
                @Override
                public boolean onMenuItemClick(MenuItem item) {
                    return false;
                }
            });
複製程式碼

Menu的一些操作

 /**
     * 每次選單被關閉時呼叫.
     *選單被關閉有三種情形:
     *1.展開menu的按鈕被再次點選
     *2.back按鈕被點選
     *3.使用者選擇了某一個選單項
     */
    @Override
    public void onOptionsMenuClosed(Menu menu) {
        super.onOptionsMenuClosed(menu);
    }
  /**
     * 在onCreateOptionsMenu執行後,選單被顯示前呼叫;如果選單已經被建立,則在選單顯示前被呼叫。 同樣的,
     * 返回true則顯示該menu,false 則不顯示; (可以通過此方法動態的改變選單的狀態,比如載入不同的選單等)
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        return super.onPrepareOptionsMenu(menu);
    }
  /**
     * 顯示menu的icon,通過反射,設定Menu的icon顯示.
     * @param view
     * @param menu
     * @return
     */
    @Override
    protected boolean onPrepareOptionsPanel(View view, Menu menu) {
        if (menu != null) {
            if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
                try{
                    Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
                    m.setAccessible(true);
                    m.invoke(menu, true);
                } catch (Exception e) {
                    Log.e(getClass().getSimpleName(), "onMenuOpened...unable to set icons for overflow menu", e);
                }
            }
        }
        return super.onPrepareOptionsPanel(view, menu);
    }

複製程式碼

style的配置:

style的配置感覺挺噁心的.坑挺多的

基本的配置:

 <style name="toolbar">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        //設定toolbar的最小高度.這樣設定的意義,就是解決適配的問題,標準md高度.
        <item name="android:minHeight">?attr/actionBarSize</item>
        <item name="android:background">@color/colorPrimary</item>
          //設定沉浸式,
        <item name="android:fitsSystemWindows">true</item>
    </style>
複製程式碼

style的有些方法必須是Sdk21以上才能用,所以得這樣

QQ圖片20170227110814.png

建立一個values-v21的資料夾,再寫一個style. 還得做一些配置. 普通values中的style改成如下:

 <style name="toolbar">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:minHeight">?attr/actionBarSize</item>
        <item name="android:background">@color/colorPrimary</item>

        <item name="android:fitsSystemWindows">true</item>
    </style>
    <style name="base_toolbar" parent="toolbar"/>

複製程式碼

values-v21中的style如下:

 <style name="base_toolbar" parent="@style/toolbar">
        <item name="android:elevation">3dp</item>
        <item name="android:navigationIcon">?attr/homeAsUpIndicator</item>
    </style>
複製程式碼

使用這個style

   style="@style/base_toolbar"
複製程式碼

-----------------------------------------------分割線 -----------------------------------------------

現在來說說style中的坑:
1.app:theme ------------------toolbar的主題
2.app:popupTheme------------彈出的menu的主題.
   <!-- ToolBar樣式 .-->
    <style name="toolbar_theme" parent="@style/ThemeOverlay.AppCompat.Dark">
        <item name="android:textSize">18sp</item> <!--  字型大小-->
    </style>
  <!-- ToolBar選單樣式.-->
    <style name="popup_theme" parent="@style/ThemeOverlay.AppCompat.Dark">
        <item name="android:background">@android:color/white</item>
        <item name="android:textColor">@android:color/holo_red_dark</item>
    </style>
複製程式碼
繼承的是ThemeOverlay.AppCompat:

如果使用的是Dark系列的主題,那麼字型就是白色的.menu選單背景是黑色

Paste_Image.png

如果使用的是Light系列的主題,那麼字型和圖示就是黑色的.menu選單背景是白色

Paste_Image.png

下面說說這裡坑的地方:

1.修改toolbar的字型
<!-- ToolBar樣式 .-->
   <style name="toolbar_theme" parent="@style/ThemeOverlay.AppCompat.Light">
        <!--修改toolbar的Title顏色.正確-->
       <item name="android:textColorPrimary">@android:color/holo_red_dark</item>
       <!--錯誤,網上有些資料是這樣的,然而這樣寫編譯都會報錯-->
       <item name="textColorPrimary">@android:color/holo_red_dark</item>
       <!--修改toolbar的subtitle(小標題)顏色.正確-->
       <item name="subtitleTextColor">@android:color/holo_red_dark</item>
   </style>
複製程式碼
2.修改Toolbar的menu摺疊圖示和NavigationIcon的顏色
<style name="toolbar_theme" parent="@style/ThemeOverlay.AppCompat.Light">
          <!-正確,這個要求Api大於21-->
        <item name="android:colorControlNormal">@android:color/holo_red_dark</item>
        <!--這個也正確,用這個吧-->
        <item name="colorControlNormal">@android:color/holo_red_dark</item>
    </style>
複製程式碼

效果圖:

Paste_Image.png

3.修改menu的字型顏色(大坑):

既然是menu選單的內容,當然是修改popup_theme了.

找了很多資料,發現都不正確. 比如說設定android:actionMenuTextColor這個屬性

 <style name="popup_theme" parent="@style/ThemeOverlay.AppCompat.Light">
        <!--這個不對,不生效-->    
      <item name="android:actionMenuTextColor">@android:color/holo_red_dark</item>
    
    </style>
複製程式碼

後來乾脆一個個屬性試好了,發現其實沒那麼麻煩..

  <!-- ToolBar選單樣式.-->
    <style name="popup_theme" parent="@style/ThemeOverlay.AppCompat.Light">
      <!--設定背景-->
       <item name="android:background">@android:color/white</item>
       <!--設定字型顏色-->
      <item name="android:textColor">@android:color/holo_red_dark</item>
    </style>
複製程式碼

效果:

Paste_Image.png

4.menu選單的顯示位置

預設是這樣的:

Toolbar設定掉坑總結
會遮蓋toolbar

可以修改popuptheme的這個屬性來設定:

  <!--設定不覆蓋錨點-->
   <item name="overlapAnchor">false</item>
複製程式碼

有些資料說要這麼設定:

    <!-- ToolBar選單樣式.-->
 <style name="popup_theme" parent="@style/ThemeOverlay.AppCompat.Light">
        <item name="actionOverflowMenuStyle">@style/OverflowMenuStyle</item>
 </style>
 <style name="OverflowMenuStyle"parent="Widget.AppCompat.Light.PopupMenu.Overflow">
        <!--設定不覆蓋錨點-->
        <item name="overlapAnchor">false</item>
 </style>
複製程式碼

其實沒必要,可以直接在app:popupTheme的style裡面設定overlapAnchor這個屬性就好了. 但是,一定是要在app:popupTheme的style裡面設定,而不是app:theme的style裡面設定.

最終效果如下:

Paste_Image.png

最終效果的style程式碼:

    <style name="toolbar">
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">wrap_content</item>
        <item name="android:minHeight">?attr/actionBarSize</item>
        <item name="android:background">@color/colorPrimary</item>
        <item name="android:fitsSystemWindows">true</item>
    </style>
   <style name="base_toolbar" parent="toolbar"/></style>
     <!-- ToolBar樣式.-->
    <style name="toolbar_theme" parent="@style/ThemeOverlay.AppCompat.Light">
        <!--修改toolbar的Title(大標題)顏色-->
        <item name="android:textColorPrimary">@android:color/holo_red_dark</item>
        <!--修改toolbar的subtitle(小標題)顏色-->
        <item name="subtitleTextColor">@android:color/holo_red_dark</item>
        <!--修改toolbar的圖示顏色.-->
        <item name="colorControlNormal">@android:color/holo_red_dark</item>
    </style>
    <!-- ToolBar選單樣式.-->
    <style name="popup_theme" parent="@style/ThemeOverlay.AppCompat.Light">
        <!--設定背景-->
        <item name="android:background">@android:color/white</item>
        <!--設定字型顏色-->
        <item name="android:textColor">@android:color/holo_red_dark</item>
        <!--設定不覆蓋錨點-->
        <item name="overlapAnchor">false</item>
    </style>

複製程式碼

values-v21的style的程式碼:

  <style name="base_toolbar" parent="@style/toolbar">
        <item name="android:elevation">6px</item>
        <item name="android:navigationIcon">?attr/homeAsUpIndicator</item>
    </style>
複製程式碼

toolbar佈局的程式碼

<android.support.v7.widget.Toolbar
    android:id="@+id/tl_costom"
    style="@style/base_toolbar"
    app:theme="@style/toolbar_theme"
    app:popupTheme="@style/popup_theme"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
</android.support.v7.widget.Toolbar>
複製程式碼
到此一般的基本設定就寫完了.

------------------------------------------------------------------------------------------`

2017-6-21更新

fragment使用menu選單的正確姿勢

坑點:

 @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
    }
複製程式碼
1.在frgament裡面這個方法就是坑爹的
2.即使 setHasOptionsMenu(true); 也不建立,跳個頁面返回回來結果有了.
3.但如果是viewpager+多frgament這種.會造成錯亂.其他的frgament也會有menu
4.style配置無效!!

正確姿勢:

哥直接程式碼設定還不行嘛.不配置了

以下程式碼在setSupportActionBar()之前呼叫

//設定popupstyle.比如是否覆蓋描點,背景,字型顏色什麼的.必須在inflateMenu()之前設定
 mToolbar.setPopupTheme(R.style.popup_theme);
//用Toolbar建立menu
 mToolbar.inflateMenu(R.menu.main_home_menu);
//拿到Menu 
Menu menu = mToolbar.getMenu();
//下面的這段程式碼是為了讓menu選單摺疊樣式時,展開能顯示icon圖示.不然icon圖示不會顯示.(感覺很坑)
if (menu != null) {
     if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
           try {
                    MenuBuilder menuBuilder = (MenuBuilder) menu;
                    menuBuilder.setOptionalIconsVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
        }
}

複製程式碼

您的喜歡與建議是我最大的動力-_-

相關文章