Android Support Library 23.2用法簡析

寫在前面的幾句話

<p>
前幾天谷歌發布了android-support-library-23.2支持庫,這一次23.2版本增加了一些新的支持庫以及新的功能。接下來這篇文章,就是對這些新功能部分做簡單的用法介紹

這次更新增加的東西有:

  • Support Vector Drawables and Animated Vector Drawables
  • AppCompat DayNight theme
  • Design Support Library: Bottom Sheets
  • Support v4: MediaBrowserServiceCompat
  • RecyclerView
  • Custom Tabs
  • Leanback for Android TV

需要添加的依賴如下:

compile 'com.android.support:appcompat-v7:23.2.0'
compile 'com.android.support:design:23.2.0'
compile 'com.android.support:support-vector-drawable:23.2.0'
compile 'com.android.support:animated-vector-drawable:23.2.0'

分別說明使用方法

1.Support Vector Drawables and Animated Vector Drawables(支持矢量圖片和矢量圖片動畫)

<p>
其實前面的文章關于Metarial Design動畫中也有介紹到矢量圖與矢量圖的動畫,但是那是局限于5.0以上的設備才可以使用,沒想到這么快就Support包就向下支持了,其實使用方法也很類似,大家可以參考下那篇文章,

想在低版本使用還需要做點東西:

AndroidStudio1.4已經引入過矢量繪圖支持在構建時生成PNG圖像。要想禁用此功能(并想使用最新支持庫),你需要在你的build.gradle里面添加vectorDrawables.useSupportLibrary = true

// Gradle Plugin 2.0+  
 android {  
   defaultConfig {  
     vectorDrawables.useSupportLibrary = true  
    }  
 }

你會發現這個新的屬性只在AndroidStudio2.0版本存在。如果您使用的是AndroidStudio1.5,需要

// Gradle Plugin 1.5  
 android {  
   defaultConfig {  
     generatedDensities = []  
  }  

  // This is handled for you by the 2.0+ Gradle Plugin  
  aaptOptions {  
    additionalParameters "--no-version-vectors"  
  }  
 }

通常需要在三個xml文件中定義可動的矢量圖:

一個矢量圖使用<vector>元素,放在res/drawable/下。

一個可動的矢量圖使用<animated-vector>元素,放在res/drawable/下。

一個或更多個動畫對象使用<objectAnimator>元素,放在res/anim/下。

可動矢量圖可以使用<group>和<path>元素。<group>元素定義一系列路徑或者子組,<path>元素定義可繪圖的路徑。

當你定義了一個想要作用動畫的矢量可繪制圖,使用android:name屬性給每個group和path指定一個唯一的名字,這樣你可以從動畫的定義中找到他們。

res/drawable/vector_drawable_cpu_ani.xml

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="64dp"
    android:height="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">

    <group android:name="cpu_box">
        <path
            android:name="cpu"
            android:fillColor="?android:textColorSecondary"
            android:pathData="
            M341.087,157.478 c7.417,0,13.435,6.018,13.435,13.435 v170.174c0,7.417-6.018,13.435-13.435,13.435 H170.913 c-7.417,0-13.435-6.018-13.435-13.435V170.913c0-7.417,6.018-13.435,13.435-13.435H341.087z
            M390.348,157.478 c0-19.785-16.041-35.826-35.826-35.826H157.479c-19.785,0-35.826,16.041-35.826,35.826v197.043 c0,19.785,16.041,35.826,35.826,35.826h197.043c19.785,0,35.826-16.041,35.826-35.826V157.478z " />
    </group>
    <group android:name="bottom">
        <path
            android:name="wires_bottom"
            android:fillColor="?android:textColorSecondary"
            android:pathData="
        M193.304,408.261V462h-17.913 v-53.739H193.304z
        M264.957,408.261V462h-17.914v-53.739H264.957z
        M300.783,408.261V462h-17.914v-53.739H300.783z
        M229.13,408.261 V462h-17.913v-53.739H229.13z
        M336.609,408.261V462h-17.914v-53.739H336.609z" />
    </group>
    <group android:name="top">
        <path
            android:name="wires_top"
            android:fillColor="?android:textColorSecondary"
            android:pathData="
        M193.304,50v53.739h-17.913V50H193.304z
        M264.957,50 v53.739h-17.914V50H264.957z
        M300.783,50v53.739h-17.914V50H300.783z
        M229.13,50v53.739h-17.913V50H229.13z
        M336.609,50v53.739 h-17.914V50H336.609z " />
    </group>
    <group android:name="right">
        <path
            android:name="wires_right"
            android:fillColor="?android:textColorSecondary"
            android:pathData="
        M408.261,318.695H462v17.914h-53.739V318.695z
        M408.261,247.043H462v17.914h-53.739V247.043z
        M408.261,211.217 H462v17.913h-53.739V211.217z
        M408.261,282.869H462v17.914h-53.739V282.869z
        M408.261,175.391H462v17.913h-53.739V175.391z" />
    </group>
    <group android:name="left">
        <path
            android:name="wires_left"
            android:fillColor="?android:textColorSecondary"
            android:pathData="
        M50,318.695h53.739v17.914H50V318.695z
        M50,247.043h53.739v17.914H50V247.043z
        M50,211.217h53.739v17.913H50V211.217z
        M50,282.869 h53.739v17.914H50V282.869z
        M50,175.391h53.739v17.913H50V175.391z" />
    </group>

</vector>

res/drawable/animated_cpu.xml

<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/vector_drawable_cpu_ani">

    <target
        android:name="top"
        android:animation="@animator/pulse_top" />

    <target
        android:name="right"
        android:animation="@animator/pulse_right" />

    <target
        android:name="left"
        android:animation="@animator/pulse_left" />

    <target
        android:name="bottom"
        android:animation="@animator/pulse_bottom" />
</animated-vector>

res/anim/anim_left.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="250"
        android:propertyName="translateX"
        android:repeatCount="infinite"
        android:repeatMode="reverse"
        android:valueFrom="0"
        android:valueTo="-10"
        android:valueType="floatType" />
</set>

最后調用

//Support Vector Drawables
app:srcCompat="@drawable/vector_drawable_cpu_ani"
// Animated Vector Drawables
app:srcCompat="@drawable/animated_cpu"
圖1 Support Vector Drawables and Animated Vector Drawables效果圖

至于pathData中的東西,其實前面也有說過SVG標準指令,這里就不做過多概述了

2.AppCompat DayNight theme(DayNight 主題)

<p>
之前有看到同事折騰這個DayNight模式折騰還蠻久,不過這次谷歌出了,倒是可以省去不少時間

DayNight主題包含DayNight.NoActionBar, DayNight.DarkActionBar, DayNight.Dialog 等等,DayNight主題支持應用切換 白天 和 夜晚 主題,根據 是否為 ‘夜晚’ 決定是否從白天主題有效的切換到夜晚主題。注意這里的DayNight主題只支持API14以上

使用方法如下:

首先要設置Application或者單獨Activity的theme為DayNight主題

themes.xml

<style name="AppTheme.DayNight.NoActionBar">
    //other
</style>

AndroidManifest,xml

android:theme="@style/AppTheme.DayNight.NoActionBar"

DayNight主題有四個的模式:

  • MODE_NIGHT_NO 始終使用天(光)的主題

  • MODE_NIGHT_YES 始終使用夜間(黑暗)的主題

  • MODE_NIGHT_AUTO 根據一天中的時間晝/夜之間的變化。

  • MODE_NIGHT_FOLLOW_SYSTEM 此設置遵循系統的設置,基本上是以MODE_NIGHT_NO為主

我們可以通過我們通過調用AppCompatDelegate.setDefaultNightMode(),與getDelegate()。setLocalNightMode()來改變

但是兩者設置是有區別的,

  • AppCompatDelegate.setDefaultNightMode()的設置是對整個App中theme為DayNight主題生效
  • getDelegate().setLocalNightMode()的設置只對于設置的地方生效

AppCompatDelegate.setDefaultNightMode()

public void ChangeDayNight(View v){
    switch (v.getId()){
        case R.id.day:
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            recreate();
            break;
        case R.id.night:
            AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            recreate();
            break;
    }
}
圖2 AppCompatDelegate.setDefaultNightMode()設置

getDelegate().setLocalNightMode()

public void ChangeDayNight(View v){
    switch (v.getId()){
        case R.id.day:
            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            recreate();
            break;
        case R.id.night:
            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            recreate();
            break;
    }
}
圖3 getDelegate().setLocalNightMode()設置

但是如果把AppCompatDelegate.setDefaultNightMode()與getDelegate().setLocalNightMode()寫在一起你就會發現一個有趣的情況

public void ChangeDayNight(View v){
    switch (v.getId()){
        case R.id.day:
            getDelegate().setLocalNightMode(AppCompatDelegate.MODE_NIGHT_NO);
            recreate();
            break;
        case R.id.night:
             AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
            recreate();
            break;
    }
}
圖4 兩種用法一起

看圖可以發現,一開始都是白天模式的,然后我先設置了day及 getDelegate().setLocalNightMode()方法,然后設置了AppCompatDelegate.setDefaultNightMode()方法,但是這里的設置為night的方法并沒有生效,但是當跳轉到另外的一個界面的時候卻發現這個界面是夜晚的模式,所以其實AppCompatDelegate.setDefaultNightMode()方法是生效了的,那么為什么在第一個界面設置AppCompatDelegate.setDefaultNightMode()方法沒有生效呢?

我們看下AppCompatDelegate.setDefaultNightMode()這個方法前面的注釋

Sets the default night mode. This is used across all activities/dialogs but can be overriden locally via {@link #setLocalNightMode(int)}.

所以其實當前Activity中getDelegate().setLocalNightMode()方法設置后會覆蓋掉AppCompatDelegate.setDefaultNightMode()方法,導致看起來好像沒有生效,其實是已經生效了的。

3.Design Support Library : Bottom Sheets (材料設計,底部表)

<p>
Design Support Library 其實準備作為Metarial Design的第四篇文章進行說明的,這里提前說明Bottom Sheets的使用

Bottom Sheets 可以在Activity,Fragment,以及Dialog中使用,使用時候繼承的父類分別是:AppCompatActivity,AppCompatFragment,AppCompatDialog

先說明Bottom Sheets在Activity中的使用

1.創建Xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="bottomshets"
        android:onClick="showBottom"
        />

    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="400dp"
        android:background="@color/colorAccent"
        app:behavior_hideable="false"
        app:behavior_peekHeight="0dp"
        app:layout_behavior="@string/bottom_sheet_behavior"
        android:orientation="horizontal"/>

</android.support.design.widget.CoordinatorLayout>

布局很簡單有一個Button 和一個linearLayout,其實是把這個LinearLayout作為底部彈出的View,但是注意LinearLayout多出了幾個新的東西

  • app:layout_behavior="@string/bottom_sheet_behavior" 這個屬性是作為Bottom Sheet必須的屬性
  • app:behavior_hideable="false" 這個屬性是當我們拖拽下拉的時候,bottom sheet是否能全部隱藏
  • app:behavior_peekHeight="0dp" 這個屬性是當Bottom Sheets關閉的時候,底部下表我們能看到的高度

另外這里必須用CoordinatorLayout才可以生效

2.代碼中

final BottomSheetBehavior behavior = BottomSheetBehavior.from(mlinearlayout);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);

mlinearlayout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }
});

這里是通過附加一個BottomSheetBehavior 給CoordinatorLayout的子視圖,behavior.setState()是設置Bottom Sheet的狀態,Bottom Sheet的狀態有5種:

  • STATE_COLLAPSED: 關閉Bottom Sheets,顯示peekHeight的高度,默認是0
  • STATE_DRAGGING: 用戶拖拽Bottom Sheets時的狀態
  • STATE_SETTLING: 當Bottom Sheets view擺放時的狀態。
  • STATE_EXPANDED: 當Bottom Sheets 展開的狀態
  • STATE_HIDDEN: 當Bottom Sheets 隱藏的狀態

我們可以通過setBottomSheetCallback來監聽Bottom Sheet的回調

behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
    @Override
    public void onStateChanged(View bottomSheet, int newState) {   
    }
    @Override
    public void onSlide(View bottomSheet, float slideOffset) {
    }
});

onSlide方法是拖拽中的回調可以根據slideOffset做動畫,onStateChanged方法可以監聽到狀態的改變

圖5 Activity中BottomSheet的使用效果圖

至于Fragment的使用則與Activity中相似,就不做聲明,參考Activity的使用即可。

接下來說明下Dialong的使用方式:

final BottomSheetDialog dialog = new BottomSheetDialog(this);
View view = LayoutInflater.from(this).inflate(R.layout.bottomdialog_layout, null);
LinearLayout linearLayout = (LinearLayout)view.findViewById(R.id.dialog_layout);
linearLayout.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        dialog.dismiss();
    }
});
dialog.setContentView(view);
dialog.show();

使用其實與普通的Dialog差不多

效果如下:

圖6 Dialog中BottomSheet的使用效果圖

如果要在Bottom Sheets里面使用滑動的布局,則需要使用NestedScrollView, RecyclerView,或者ListView/ScrollView on API 21+

4.Support v4: MediaBrowserServiceCompat

<p>
該Support v4庫用作許多支持庫的基礎,并且為一些新版本介紹的特征提供支持(backports)。添加到以前發布的MediaSessionCompat類,為媒體播放了提供了堅實的基礎,這個版本增加了MediaBrowserServiceCompat和MediaBrowserCompat提供,帶來了最新的API兼容的解決方案(甚至沒有在L設備上加)支持API4+。這使得我們更容易地在Android上支持媒體的播放和在Android Wear上瀏覽媒體,為我們提供了一個標準的接口,讓你的媒體播放服務與界面連起來。

由于我不是很關心,所以沒有了解這方法的東西,跳過

5.RecyclerView

<p>
RecyclerView組件為我們提供了靈活的創建列表和網格以及動畫的特性。這個版本帶來一個激動人心的新特性LayoutManager API:自動測量!!!這允許RecyclerView尺寸大小根據其內容的大小尺寸定制。這意味著,先前不可用的情況,例如使用WRAP_CONTENT為尺寸的RecyclerView,現在都是可能的。你會發現所有內置的布局管理現在都支持自動測量。由于這種變化,一定要確保你的item的布局屬性:以前被忽視的布局參數(如MATCH_PARENT的滾動方向)現在將不一樣。如果你有一個自定義的LayoutManager并且不是基于之前的拓展,有一個選擇就是你可以調用setAutoMeasureEnabled(true),以及做一些小的變化(詳情見Javadoc)來支持新特性注意,雖然RecyclerView支持動畫,但是他不支持自己動畫邊界變化,如果你想對RecyclerView邊界進行動畫處理,你可以使用 Transition APIs.

這里變化從使用代碼層面來說沒有什么太多變化,就不上代碼了。

6.Custom Tabs(自定義選項卡)

爛尾很久了,這里看了下沒有太多資料,最近又比較忙,準備下次開篇專門的文章介紹下,好的就這樣了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容