轉載自Keegan小鋼
原文鏈接:http://keeganlee.me/post/android/20151031
前面鋪墊了那麼多,終於要講到本系列的終篇,整合所有資源,定義成統一的樣式。 哪些該定義成統一的樣式呢?舉幾個例子吧:
- 每個頁面標題欄的標題基本會有一樣的字體大小、顏色、對齊方式、內間距、外間距等,這就可以定義成樣式;
- 很多按鈕也都使用一致的背景、內間距、文字顏色、文字大小、文字的對齊方式等,這也可以定義成樣式;
- 網路加載的進度條基本也都是一樣的,同樣可以定義成樣式;
- 不喜歡系統的彈出框樣式,那也可以自定義樣式。
樣式的定義
Android的樣式一般定義在res/values/styles.xml文件中,其中有一個根元素<resource>,而具體的每種樣式定義則是通過<resource>下的子標籤<style>來完成,<style>通過添加多個<item>來設置樣式不同的屬性。 另外,樣式是可以繼承的,可通過<style>標籤的parent**屬性聲明要繼承的樣式,也可通過點前綴 (.) 繼承,點前面為父樣式名稱,後面為子樣式名稱。點前綴方式只適用於自定義的樣式,若要繼承Android內置的樣式,則只能通過parent屬性聲明。
用個實例說明具體的用法吧,以下程式碼為Android 5.0系統默認的按鈕樣式:
<style name="Widget.Material.Button">
<item name="background">@drawable/btn_default_material</item>
<item name="textAppearance">?attr/textAppearanceButton</item>
<item name="minHeight">48dip</item>
<item name="minWidth">88dip</item>
<item name="stateListAnimator">@anim/button_state_list_anim_material</item>
<item name="focusable">true</item>
<item name="clickable">true</item>
<item name="gravity">center_vertical|center_horizontal</item>
</style>
其中,stateListAnimator指定狀態改變時的動畫,button_state_list_anim_material的程式碼如下:
<!-- res/anim/button_state_list_anim_material.xml -->
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:state_enabled="true">
<set>
<objectAnimator
android:propertyName="translationZ"
android:duration="@integer/button_pressed_animation_duration"
android:valueTo="@dimen/button_pressed_z_material"
android:valueType="floatType" />
<objectAnimator
android:propertyName="elevation"
android:duration="0"
android:valueTo="@dimen/button_elevation_material"
android:valueType="floatType" />
</set>
</item>
<!-- base state -->
<item android:state_enabled="true">
<set>
<objectAnimator
android:propertyName="translationZ"
android:duration="@integer/button_pressed_animation_duration"
android:valueTo="0"
android:startDelay="@integer/button_pressed_animation_delay"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="elevation"
android:duration="0"
android:valueTo="@dimen/button_elevation_material"
android:valueType="floatType" />
</set>
</item>
<item>
<set>
<objectAnimator
android:propertyName="translationZ"
android:duration="0"
android:valueTo="0"
android:valueType="floatType"/>
<objectAnimator
android:propertyName="elevation"
android:duration="0"
android:valueTo="0"
android:valueType="floatType"/>
</set>
</item>
</selector>
可以看到,每種狀態的動畫為屬性動畫集,屬性動畫的用法請參考Property Animation篇。 現在我想繼承Widget.Material.Button樣式,改變背景和文字顏色,那麼,程式碼如下:
<!-- res/values/styles.xml -->
<resources>
<style name="ButtonNormal" parent="@android:style/Widget.Material.Button" >
<item name="android:background">@drawable/bg_btn_selector</item>
<item name="android:textColor">@color/text_btn_selector</item>
</style>
</resources>
其中,@drawable/bg_btn_selector和@color/text_btn_selector**的實現請參照selector篇。 有些按鈕,我只想改變文字顏色,但背景想讓它透明,這時就可以用點前綴的方式繼承以上的樣式,程式碼如下:
<!-- res/values/styles.xml -->
<resources>
<style name="ButtonNormal" parent="@android:style/Widget.Material.Button">
<item name="android:background">@drawable/bg_btn_selector</item>
<item name="android:textColor">@color/text_btn_selector</item>
</style>
<style name="ButtonNormal.Transparent">
<item name="android:background">@drawable/bg_btn_transparent</item>
<item name="android:textColor">@color/text_btn_selector</item>
</style>
</resources>
引用的時候只要在相應的Button裡添加style就可以了,程式碼如下:
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onAction"
android:text="@string/btn_action"
style="@style/ButtonNormal.Transparent" />
有時候,定義的樣式太多,如果都放在styles.xml文件裡,那這文件也太臃腫了。因此,可以將樣式分類拆分成多個文件。Android系統本身也拆分為多個文件存放的,如下列表全都是樣式文件:
styles.xml
styles_device_defaults.xml
styles_holo.xml
styles_leanback.xml
styles_material.xml
styles_micro.xml
themes.xml
themes_device_defaults.xml
themes_holo.xml
themes_leanback.xml
themes_material.xml
themes_micro.xml
其中,主要分為兩大類,styles定義了簡單的樣式,而themes則定義了主題。
主題
以上的簡單例子只用於單個View,這是樣式最簡單的用法。但樣式的用法不只是用於單個View,也能用於Activity或整個Application,這時候需要在相應的<activity>標籤或<application>標籤裡設置android:theme屬性,引用的其實也是style,但一般稱為主題。
Android系統提供了多套主題,查看Android的frameworks/base/core/res/res/values目錄,就會看到有以下幾個文件(目前為止):
- themes.xml:低版本的主題,目標API level一般為10或以下
- themes_holo.xml:從API level 11添加的主題
- themes_device_defaults.xml:從API level 14添加的主題
- themes_material.xml:從API level 21添加的主題
- themes_micro.xml:應該是用於Android Wear的主題
- themes_leanback.xml: 還不清楚什麼用
不過在實際應用中,因為大部分都採用兼容包的,一般都會採用兼容包提供的一套主題:Theme.AppCompat。AppCompat主題默認會根據不同版本的系統自動匹配相應的主題,比如在Android 5.0系統,它會繼承Material主題。不過這也會導致一個問題,不同版本的系統使用不同主題,就會出現不同的體驗。因此,為了統一用戶體驗,最好還是自定義主題。
自定義主題也很簡單,只要繼承某一父主題,然後在<activity>標籤或<application>中引用就可以了。 主題的定義示例如下:
<resources>
<style name="AppTheme" parent="Theme.AppCompat">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="windowAnimationStyle">@style/WindowAnimation</item>
</style>
<!-- Standard animations for a full-screen window or activity. -->
<style name="WindowAnimation" parent="@android:style/Animation.Activity">
<item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
<item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
<item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
<item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
</style>
</resources>
其中,WindowAnimation重新指定了Activity的轉場動畫,以下為activity_close_exit的示例程式碼:
<!-- res/anim/activity_close_exit.xml -->
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false"
android:zAdjustment="top">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:interpolator="@interpolator/decelerate_quart"
android:fillEnabled="true"
android:fillBefore="false"
android:fillAfter="true"
android:duration="200" />
<translate
android:fromYDelta="8%"
android:toYDelta="0"
android:fillEnabled="true"
android:fillBefore="true"
android:fillAfter="true"
android:interpolator="@interpolator/decelerate_quint"
android:duration="350" />
</set>
這是比較簡單的視圖動畫,視圖動畫具體用法可參考View Animation篇。 接著,若要使用到整個Application,則在AndroidManifest.xml的<application>標籤設置android:theme**屬性,示例程式碼如下:
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- activity here -->
</application>