當前位置:
首頁 > 最新 > Material Design 控制項之 Toolbar 非完全解析

Material Design 控制項之 Toolbar 非完全解析

一、Toolbar 出現的背景

Toolbar 是 Android5.0 中新引入的一個控制項,其出現的目的就是為了取代 ActionBar。

Actionbar 在 Android3.0 推出的目的就是為了在 UI 界面中引入一個全局導航的功能,取代 Android3.0 之前的標題欄。並且在剛推出不久就發布了兼容到 API 7 的兼容包,但是很多應用都沒有使用 Actionbar。

原因是 Actionbar 的界定很模糊,因為 Android 系統中把界面分成兩大部分,一部分是 System UI,主要由 Statusbar 和 Android4.0 以後出現的由虛擬按鍵構成的導航欄為主,對於系統 UI 來說,Android 不允許應用開發者對其進行完全控制,在 Android5.0 之後甚至不讓開發者控制狀態欄;另一部分就是應用 UI,對於這部分 UI,開發者擁有完全控制權。

而 Actionbar 在顯示上應該算是應用 UI 的一部分,但是開發者又不能對其進行完全控制,因為它畢竟是由系統創建並對其進行相關參數的初始化。所以在實際開發中,很多開發者都是用布局生成一個模擬的 Actionbar 來代替系統的 Actionbar,基於這一點,Android 在5.0後推出一個新的控制項 Toolbar 來取代 ActionBar。

二、Toolbar 的使用

Toolbar

1)導包

直接在 Module 的 build.gradle 文件中添加依賴

dependencies { compile com.android.support:appcompat-v7:25.3.1 }2)設置 Theme

要想使用 Toolbar 代替 Actionbar,必須使用 Theme.AppCompat 主題中沒有 Actionbar 的主題,把 Actionbar 隱藏掉,否則會造成衝突,NoActionbar 的主題對兩個 Window 屬性進行了重寫:

false true

經過實際測試,發現其實只需要設置true即可

3)xml 文件中添

不同於 Actionbar ,系統會自動根據設置的 Theme 創建不同樣式的 Actionbar 添加到界面中,Toolbar 需要像普通控制項一樣在布局文件中添加:

給 Toolbar 設置屬性有三種方式,可以結合使用:

1、調用 setSupportActionbar/setActionbar 方法和 ·getSupportActionbar/getActionbar 把 Toolbar 作為 Actionbar 處理public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); } }

通過 findViewById 方法獲取到 xml 文件中添加的 Toolbar 控制項,然後調用 setSupportActionbar 方法,如果只支持 5.0 以上系統調用 setActionbar 方法,這個方法是把 Toolbar 當作 Actionbar 來處理,把系統給 Actionbar 設置的相關初始參數設置給 Toolbar,之前關於 Actionbar 的大部分操作都會應用在 Toolbar 上。

setSupportActionbar 是 AppCompatActivity 中的方法,所以使用這種方式的 Activity 必須繼承 AppCompatActivity。

這裡的參數是 Toolbar 而並非 Actionbar,簡單看一下源碼:

AppCompatActivity#setSupportActionbarpublic void setSupportActionBar(@Nullable Toolbar toolbar) { getDelegate().setSupportActionBar(toolbar); }

只是簡單地調用了 AppCompatDelegate 的 setSupportActionbar 方法:

AppCompatDelegateImplV7#setSupportActionbar

AppCompatDelagate 類是個抽象類,它的實現類 AppCompatDelegateImplV7 實現了 setSupportActionbar 方法:

@Override public void setSupportActionBar(Toolbar toolbar) { if (!(mOriginalWindowCallback instanceof Activity)) { return; } final ActionBar ab = getSupportActionBar(); if (ab instanceof WindowDecorActionBar) { throw new IllegalStateException("This Activity already has an action bar supplied " + "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " + "windowActionBar to false in your theme to use a Toolbar instead."); } ToolbarActionBar tbab = new ToolbarActionBar(toolbar, ((Activity) mContext).getTitle(), mAppCompatWindowCallback); setSupportActionBar(tbab); mWindow.setCallback(tbab.getWrappedWindowCallback()); tbab.invalidateOptionsMenu(); }

這段方法的邏輯非常簡單,首先會判斷當前的窗口回調是否是一個

Activity 對象,因為只有 Activity 才能夠支持創建 ActionBar,不是的話就返回,然後就會嘗試去獲取當前的 ActionBar,如果發現當前 Activity 中已經有了 ActionBar 就會拋出一個異常,這就是我們要設置 Toolbar 來替代 ActionBar 那麼就必須去掉原有的

ActionBar 的原因,當然如果只是將 Toolbar 作為一個普通的控制項,就不是必須的了。

然後將傳入的 Toolbar 對象作為入參構造了一個 ToolbarActionBar 對象,隨後馬上調用了 setSupportActionBar 方法並將這個

ToolbarActionBar 對象傳入,來看 ToolbarActionBar 類:

ToolbarActionBarpublic class ToolbarActionBar extends ActionBar { // ......省略一些代碼...... public ToolbarActionBar(Toolbar toolbar, CharSequence title, Window.Callback callback) { mDecorToolbar = new ToolbarWidgetWrapper(toolbar, false); mWindowCallback = new ToolbarCallbackWrapper(callback); mDecorToolbar.setWindowCallback(mWindowCallback); toolbar.setOnMenuItemClickListener(mMenuClicker); mDecorToolbar.setWindowTitle(title); } // ......省略大量代碼...... }

在 ToolbarActionBar 的構造方法中,又將 toolbar 作為入參構造了一個 ToolbarWidgetWrapper 對象,從類名里就可以看出,這個

ToolbarWidgetWrapper 是個包裝類,它持有 Toolbar 的引用,其實用心觀察 ToolbarActionBar 這個類你會發現他是一個代理類,其中大部分方法都是間接由 mDecorToolbar 這個對象調用,mDecorToolbar 對象的實際類型就是剛才我們所說的

ToolbarWidgetWrapper,而引用類型則是 DecorToolbar,ToolbarActionBar 這個類以委託代理的方式將自身的功能交由

mDecorToolbar 實現:

public class ToolbarActionBar extends ActionBar { // ......省略一些代碼...... @Override public void setIcon(int resId) { mDecorToolbar.setIcon(resId); } @Override public void setIcon(Drawable icon) { mDecorToolbar.setIcon(icon); } @Override public void setLogo(int resId) { mDecorToolbar.setLogo(resId); } @Override public void setLogo(Drawable logo) { mDecorToolbar.setLogo(logo); } // ......省略一些代碼...... }

mDecorToolbar 的方法中對持有的 Toolbar 成員變數進行相關設置。

也可以調用 getSupportActionbar 方法獲取被當做 Actionbar 處理的 Toolbar 對象,並調用 Actionbar 的相關方法對 Toolbar 進行操作,這個時候 Toolbar 就是一個 Actionbar。

2、調用 Toolbar 的相關方法

Toolbar 自身也對外提供了一系列的方法對 Toolbar 進行相關設置,這個時候不需要調用 setSupportActionbar 方法,Activity 也就不必非要繼承 AppCompatActivity,而且即使不隱藏 Actionbar,也不會造成衝突報錯,但是 Actionbar 會佔用 Toolbar 的位置,將 Toolbar 擠到下面去,所以作為導航欄使用的話,一般還是要隱藏掉 Actionbar。

//設置導航圖標 setNavigationIcon(@DrawableRes int resId) setNavigationIcon(@Nullable Drawable icon) setNavigationOnClickListener(OnClickListener listener) //設置 Logo setLogo(@DrawableRes int resId) setLogo(Drawable drawable) //設置標題 setTitle(@StringRes int resId) setTitle(CharSequence title) //設置標題文本顏色 setTitleTextColor(@ColorInt int color) //設置標題外觀,包括字體顏色、大小、樣式等 setTitleTextAppearance(Context context, @StyleRes int resId) //設置標題邊距像素 setTitleMargin(int start, int top, int end, int bottom) setTitleMarginStart(int margin) setTitleMarginTop(int margin) setTitleMarginEnd(int margin) setTitleMarginBottom(int margin) //設置副標題 setSubtitle(@StringRes int resId) setSubtitle(CharSequence subtitle) //設置副標題文本顏色 setSubtitleTextColor(@ColorInt int color) //設置副標題外觀,包括字體顏色、大小、樣式等 setSubtitleTextAppearance(Context context, @StyleRes int resId) //載入菜單 inflateMenu(@MenuRes int resId) //監聽菜單點擊 setOnMenuItemClickListener(OnMenuItemClickListener listener) //設置彈出菜單主題 setPopupTheme(@StyleRes int resId) //設置溢出菜單圖標 setOverflowIcon(@Nullable Drawable icon)3、在 xml 文件中設置屬性

就像普通控制項一樣,需要注意的是一些屬性的命名空間並不是 android ,需要在根布局聲明自定義的命名空間,比如這裡使用 app:

xmlns:app="http://schemas.android.com/apk/res-auto"

這裡的屬性是很多的:

//應用圖標、導航圖標、收縮圖標 app:logo="" app:logoDescription="" app:navigationIcon="" app:navigationContentDescription="" app:collapseIcon="" app:collapseContentDescription="" //樣式 app:theme="" //彈窗樣式 app:popupTheme="" //標題樣式 app:title="" app:titleTextAppearance="" app:titleTextColor="" app:titleMargin="" app:titleMargins="" app:titleMarginStart="" app:titleMarginTop="" app:titleMarginBottom="" app:titleMarginEnd="" //副標題樣式 app:subtitle="" app:subtitleTextAppearance="" app:subtitleTextColor="" //按鈕 app:buttonGravity="" app:maxButtonHeight="" //一些邊距 app:contentInsetEnd="" app:contentInsetLeft="" app:contentInsetRight="" app:contentInsetStart="" app:contentInsetEndWithActions="" app:contentInsetStartWithNavigation="" app:paddingEnd="" app:paddingStart=""app:popupTheme 和 app:theme

app:popupTheme 用來設置溢出菜單的樣式,通常繼承一個 ThemeOverlay.AppCompat 主題,當然並不是必須的,然後重寫相關屬性:

@color/colorAccent @color/colorPrimary 22sp22sp #00FF00自定義View

參考:Toolbar:上位的小三

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

努比亞真·旗艦Z17,配備三星快閃記憶體反超S8
震驚!iOS 系統居然自帶懸浮窗口調試工具
使用CNN+Auto-Encoder 實現無監督Sentence Embedding
用Instrumentation改良monkey工具實戰
理解高斯混合模型

TAG:推酷 |

您可能感興趣

淺談 Material Design iCourt技術
Linux/Windows等Chrome獲Material Design更新
Chrome獲Material Design全新升級
關於未經授權使用Materialise Mimics Innovation Suite軟體舉辦培訓的嚴正聲明
Chrome部署Material Design:似Firefox早期版本
Chrome部署Material Design:標籤欄類似於Firefox早期版本
可以對唯物主義者示現神通嗎Can I perform supernatural power to the materialist
Nanophotonics-Comsol模擬石墨烯Graphene超材料metamaterial
谷歌Material Design 2曝光
Django Admin的新皮膚,Google Material 風格皮膚
數控加工結合3D列印,看看Materialize與HCL Technologies碰出什麼火花
Material Science:讓紅外遁形
Google發布了一套名為Material Theming的新工具
一口吃掉 Material Design
全新視覺設計,Google Play商店Material Design新版曝光
Google Material Design 2 曝光:新配色 新圖標
Advanced Healthcare Materials:納米發電機在生物醫學領域的應用
npj Computational Materials:快速準確預測晶格熱導率的「小技巧」
Biomaterials:肺上皮再生過程中,Fibrillin-2和Tenascin-C消除了年齡差距的影響
Advanced Healthcare Materials:組裝的納米生物材料可用於同時提高光動治療效率與治療深度