Material適配2 - 高級篇


版權聲明:

歡迎轉載,但請保留文章原始出處

作者:GavinCT

出處:http://www.cnblogs.com/ct2011/p/4493439.html

繼續Material系列,先從Toolbar講起

ActionBar --> Toolbar

在使用ActionBar的時候,一堆的問題:這個文字能不能定制,位置能不能改變,圖標的間距怎么控制神馬的,由此暴露出了ActionBar設計的不靈活。
在上一篇中,我們只是簡單使用了AppCompatActivity,他使用的仍然是ActionBar
官方在21以后提供了ToolBar。
Toolbar之所以靈活,是因為它其實就是一個ViewGroup,我們在使用的時候和普通的組件一樣,在布局文件中聲明。

主題使用

使用Toolbar時,如果單純的當作控件來使用,主題是不需要單獨設置的。
但是如果想用他來替代ActionBar,
那么需要配置為Theme.AppCompat.NoActionBar主題,
或者在主題中加入

<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>

(兩個都必須有,上一篇已經提到沒有windowNoTitle時會報錯)
這里推薦使用第一種方式。

常用的配置

Toolbar因為經常被用來替代ActionBar,所以一般項目里都會抽取出來,以便include。
可能有人會說,既然還是用來替換ActionBar,那我項目里直接不動ActionBar不就完了?
對,一般情況下是沒有問題的,但是有些界面需要借助Toolbar靈活性的時候,你就被迫要換成Toolbar了。
先來看Toolbar常用代碼:

include_toolbar.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:minHeight="?attr/actionBarSize" />

配置中需要注意的是theme和popupTheme,我們來仔細看下,先從View的theme說起。

View的theme

Android 5.0引入一個全新的特性,允許你對view設置theme,這種設置會影響控件及其包含的子控件。
使用AppCompat v22.1.x 后,也可以給你 layout 里的任意視圖設置主題。
只要使用 android:theme 這個屬性就好,新版本的兼容庫可以在 compat 和 framework 之間無縫地切換功能。

實現原理

這是因為有ContextThemeWrapper類,這個類API v1的時候就有了。
他包裹(wrap)一個存在的Context(這里指你的Activity),之后覆蓋(overlay)一個新的主題在當前Context的主題之上,這也是為什么叫ThemeOverlay。

Toolbar常用的ThemeOverlay

  • ThemeOverlay.AppCompat.Light.ActionBar
  • ThemeOverlay.AppCompat.Dark.ActionBar

android:theme 與 app:theme

在AppCompat v21里,提供了一個快速方便的方法設置Toolbar的主題,使用app:theme。

而新版本22.1.x中,AppCompat 允許對 Toolbar 使用android:theme代替app:theme
最好的一點是:它會自動繼承父視圖的theme ,並且兼容所有APIv11以上的設備。
示例:

<Toolbar
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <!-- This TextView inherits its theme from the parent Toolbar -->
    <TextView android:text="I'm light!" />

</Toolbar>

對於運行 API v10 甚至更老的設備來說,你也可以使用android:theme屬性, 不過它不會繼承父視圖theme。
這就意味着你要么重新考慮你的布局,要么為每一個子視圖都設置上 android:theme 屬性。(這樣做效率真的很低)

總結一下:

  • 兼容 API 11 以上,推薦使用android:theme
  • 如果兼容更老的版本,推薦繼續使用app:theme

app:popupTheme

有時候我們有需求:

ActionBar文字是白的,ActionBar Overflow彈出的是白底黑字

讓ActionBar文字是白的,那么對應的theme肯定是Dark。
可是讓ActionBar彈出的是白底黑字,那么需要Light主題。
這時候popupTheme就派上用場了。

<android.support.v7.widget.Toolbar
	android:id="@+id/toolbar"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:background="?attr/colorPrimary"
	app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
	android:minHeight="?attr/actionBarSize" />

注意:
使用app:popupTheme="@style/ThemeOverlay.AppCompat.Light"而不是android:popupTheme

作為ActionBar使用

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);
}

獨立使用

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.blah);

    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);

    // Set an OnMenuItemClickListener to handle menu item clicks
    toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem item) {
            // Handle the menu item
            return true;
        }
    });

    // Inflate a menu to be displayed in the toolbar
    toolbar.inflateMenu(R.menu.your_toolbar_menu);
}

一般使用疑問

1. 沒有了splitActionBarWhenNarrow,用兩個Toolbar模擬是否可以?

不可以,這種方式是有問題的。
兩個Toolbar放在布局中后,下面的Toolbar不能頂到最左邊。
stackoverflow : How to center action menu on toolbar 中有詳細的描述。
問題中給出了SplitToolbar的解決方案,但我嘗試后發現這種解決方案仍然有輕微的偏移。

2. 使用Toolbar后,NavigationIcon不垂直居中?

NavigationIcon

Toolbar的layout_height屬性,要用“?attr/actionBarSize”而不是“?android:attr/actionBarSize”,替換后可解決NavigationIcon不垂直居中的問題。
原因是系統的actionBarSize比AppCompat中的要小。使用“?android:attr/actionBarSize”調用了較小的那個。

ActionMode配置

使用AppCompatActivity啟動

需要聲明的是,這種方法更加簡便一些,有無Toolbar都適合使用。(感謝dongorigin指正)
直接在AppCompatActivity或者ActionBarActivity中調用startSupportActionMode啟動即可。
注意這里的ActionMode是support包里的ActionMode。
這時如果你運行程序觸發ActionMode,可能會看到ActionMode和ActionBar分立成兩欄,並沒有浮在ActionBar上面。
解決的辦法很簡單,在主題中加入

<item name="windowActionModeOverlay">true</item>

即可。

給ActionMode配置主題

有些同學使用了Dark主題下的Toolbar,並且主題使用了Theme.AppCompat.Light.NoActionBar,這時候會發現ActionMode是Light主題,很難看。
那么怎么能配置成Dark主題呢?

<item name="actionBarTheme">@style/ThemeOverlay.AppCompat.Dark.ActionBar</item>

彈出菜單自定義主題

<item name="actionBarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>

ActionMode背景色替換

<!--action Mode背景-->
<item name="actionModeBackground">@color/theme_color_action_mode</item>

使用Toolbar啟動

代碼示例:

Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
toolbar.startActionMode(mActionModeCallback)

注意這里的ActionMode是view包下的,不是support v7下的。

保證ActionMode浮在ActionBar上及ActionMode背景色替換與上面方式一致,這里不再贅述,請參考上文。

如何實現和Inbox一樣的ActionMode

ActionMode_Inbox

可以看到,ActionMode開啟時,頂部的Status Bar顏色也跟着改變了

這種功能Theme中並沒有提供屬性來修改。
但是聯想到入門篇提到的代碼設置status bar顏色,這里就不難實現了。

代碼共享下:

private int mOldStatusBarColor = -1;
private void setActionModeStatusBarColor(int colorResId) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        mOldStatusBarColor = mActivity.getWindow().getStatusBarColor();
        setStatusBarColorCore(mActivity.getResources().getColor(colorResId));
    }
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setStatusBarColorCore(int color) {
    mActivity.getWindow().setStatusBarColor(color);
}
private void resetStatusBarColor() {
    if (mOldStatusBarColor != -1 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
        setStatusBarColorCore(mOldStatusBarColor);
        mOldStatusBarColor = -1;
    }
}

開啟時調用set,銷毀時調用reset即可。

P.S. : 上面的計數可以通過setTitle來完成。

網上提供的錯誤方式(已踩坑,請繞行)

保持Activity調起,使用android:windowActionModeOverlay屬性。
看似讓ActionMode浮在了ActionBar上,但其實存在很大問題。
這種方式在4.4以下會使用Holo風格(overflow圖標可以看出來,不是三個原點,是三個方塊),且ActionMode比ActionBar小一些(可以看到藍色底邊是ActionBar)

ActionMode

其他Material適配必備貼

常用效果及實現

官方參考App及示例

參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM