- Android經典應用程序開發
- 韓超編著
- 1797字
- 2019-01-09 15:18:52
2.6 樣式和主題的使用
Android中,樣式(Style)是一種用于描述一組屬性的機制,可以應用于控件(View)或者窗口。
樣式通常有兩種使用方法:
(1)在布局文件中將其應用于控件標簽,此時通常依然稱之為樣式(style)。
(2)在AndroidManifest.xml中將其應用于一個Activity或者一個application,此時通常稱之為主題(Theme)。此時相當于將這個樣式應用于其中的所有控件。
樣式可以使用系統的預置的定義,也可以自定義。預定義使用R.style類,自定義樣式通常在一個XML文件中使用<style>標簽來描述。
2.6.1 控件中的樣式
控件的樣式讓布局文件中的眾多控件擁有相同的屬性,使用樣式不僅可以減少布局文件中重復的內容,也有利于全局控制控件的外觀等公共屬性。
Android中預定義的樣式,使用R.style類中的各個成員來表示。樣式的本質是對各個XML屬性進行定義,這些XML屬性在Android中使用R.attr類來表示。
每個控件的style屬性可以用于設置它的樣式,在布局文件中可以使用類似style="@android:style/MediaButton"的方式。
例如,在某個布局文件中一個控件的定義如下所示:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:textColor="#00FF00" android:typeface="monospace" android:text="@string/hello" />
此時如果認為除了android:text之外的屬性都是作為公共的內容實現的,可以利用樣式將這個控件寫成如下方式:
<TextView style="@style/CodeFont" android:text="@string/hello" />
此時的style屬性被設置為名稱為CodeFont的樣式。可以使用res/values/目錄中的styles.xml文件進行定義,內容如下所示。
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="CodeFont" parent="@android:style/TextAppearance.Medium"> <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#00FF00</item> <item name="android:typeface">monospace</item> </style> </resources>
這里進行的自定義樣式CodeFont繼承了Android預置的樣式TextAppearance.Medium,并且定義了android:textColor等幾個屬性。定義完成后可以在各個布局文件中使用。
2.6.2 全局性質的主題
在AndroidManifest.xml中使用android:theme屬性來表示設置一種樣式作為全局性的內容。<application>和<activity>標簽具有這個屬性。此時應用的樣式中的內容,對其中的所有內容都起作用。
Android預置的主題來自android.R.style中的Theme_*等常量。除了預置的主題,可以繼承預定義樣式實現自定義主題,也可以生成完全的自定義主題。
提示:主題和樣式在本質上是相同的,都是對XML文件中的一組屬性進行默認的定義。在Android中,應用于控件時稱之為樣式(Style),應用于活動和應用時稱之為主題(Theme),后者通常比前者多了一些和窗口屬性相關的定義。
主題的設置也可以在代碼中使用,這種方式并不常用。Activity的父類ContextThemeWrapper中具有如下的方法:
public void setTheme (int resid)
1.預定義主題
android.R.style類中有屬性常量名稱為Theme_Light_NoTitleBar_Fullscreen,那么在AndroidManifest.xml使用的就是如下的格式:
需要將“_”替換成“.”,然后可以在AndroidManifest.xml中使用。大多數預定義樣式都有子類,Theme.<style>.NoTitleBar表示使用該樣式加無標題欄的效果,Theme.<style>.NoTitleBar.Fullscreen表示使用該樣式加全屏的效果。
使用不同樣式示例程序:Controls(ApiDemo=>Views=>Controls)
源代碼:
com/example/android/apis/view/Controls1.java com/example/android/apis/view/Controls2.java
布局文件:controls_1.xml
使用不同樣式的示例程序如圖2-19所示。

圖2-19 使用不同樣式的示例程序(左:Theme.Light樣式;右:默認樣式)
兩個活動使用同樣的布局文件,兩個活動的內容基本是相同的,運行的效果卻是一個白底色一個黑底色。它們的主要區別體現在AndroidManifest.xml中,如下所示:
<activity android:name=".view.Controls1" android:label="Views/Controls/1. Light Theme" android:theme="@android:style/Theme.Light"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter> </activity> <activity android:name=".view.Controls2"
android:label="Views/Controls/2. Default Theme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter> </activity>
第二個程序使用了默認樣式,而第一個程序使用了"@android:style/Theme.Light",表示使用的是Theme.Light樣式,在這種情況下底色變成了淺色的效果。
在Activity的代碼中進行的樣式設置如下所示:
protected void onCreate(Bundle savedInstanceState) { setTheme(android.R.style.Theme_NoTitleBar); super.onCreate(savedInstanceState); // ......省略活動的創建過程 }
對于代碼中的樣式設置,由于執行場合不同,因此即使將設置的代碼放在Activityd的onCreate()方法的最前面,也不能保證和在AndroidManifest.xml中設置的效果相同。
2.自定義主題
根據預定義樣式,可以通過繼承的方法實現自定義的樣式。這種自定義樣式通常只改變預定義樣式的部分屬性,一般可以在res/values/styles.xml文件中通過<style>標簽來完成定義,然后將其設置到AndroidManifest.xml中的android:theme屬性。此時使用的是類似android:theme="@style/MyTheme"的格式。
參考程序為一個對話框樣式的活動和一個自定義對話框樣式的活動。
示例程序:
DialogActivity(ApiDemo=>App=>Activity=> DialogActivity) CustomDialogActivity(ApiDemo=>App=>Activity=>CustomDialogActivity)
源代碼:com/example/android/apis/app/DialogActivity.java
布局文件:custom_dialog_activity.xml
樣式文件:res/values/styles.xml
兩個活動運行結果如圖2-20所示。

圖2-20 預定樣式和自定義樣式實現類似對話框的活動運行結果
上述兩個程序本質上都是活動,但是顯示的效果卻類似于一個對話框。透過對話框透明的部分,可以看到下面的活動。
這兩個程序的布局文件和源代碼都并無特別的地方。效果是通過在AndroidManifest.xml中設置其樣式android:theme來完成的。
AndroidManifest.xml中的定義如下所示:
<activity android:name=".app.DialogActivity" android:label="@string/activity_dialog" android:theme="@android:style/Theme.Dialog" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter> </activity> <activity android:name=".app.CustomDialogActivity" android:label="@string/activity_custom_dialog" android:theme="@style/Theme.CustomDialog“ > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter> </activity>
DialogActivity將樣式設置為“@android:style/Theme.Dialog”,表示使用預定義的樣式Theme.Dialog。
CustomDialogActivity將樣式設置為“@style/Theme.CustomDialog”,表示使用名稱為Theme.CustomDialog的自定義樣式。
CustomDialog是一個自定義樣式,在res/values/styles.xml中進行定義,如下所示:
<style name="Theme.CustomDialog" parent="android:style/Theme.Dialog"> <item name="android:windowBackground">@drawable/filled_box</item> </style>
使用“parent”表示由CustomDialog本身繼承的預定義樣式,重新定義了窗口的背景為drawable中的filled_box。這里引用了filled_box.xml文件,這個文件在res/drawable中,其中定義了相關內容。在定義的樣式中,通過設置更多的值來獲得不同的窗口效果。通過自定義樣式文件可以獲得復用效果。
提示:類似的對話框場景,前臺的程序沒有覆蓋住整個屏幕,此時后面依然處于可見狀態的活動是onPause()狀態,通常情況下,活動是完全被遮擋的,處于onStop()狀態。
3.完全自定義樣式作為主題
樣式可以在程序中全新定義,通過定制各個屬性進行定義。這些屬性來自于R.attr類中的內容進行定義。具體每一個屬性可以使用的值,可以從R.attr類的幫助文檔中找到。
由于繼承主題的方式實際上使用的是“單繼承”,因此如果想組合主題,隨心所欲地設置效果,最終的方式還是直接設置屬性。
例如,如果在res/values/styles.xml中定義如下內容:
<style name="Theme.WindowTranslucent "> <item name="android:windowIsTranslucent">true</item> </style>
定義名稱為Theme.WindowTranslucent的樣式,表示背景透明的效果。這里進行自定義的windowIsTranslucent就是R.attr類的一個成員。雖然主題只能繼承一個,但是可以進行多數量屬性的設置。
在Android程序中,當某一個活動啟動之后,可能需要使用背景透明的效果,本例用于描述背景透明的應用。
參考示例程序:
TranslucentActivity(ApiDemo=>App=>Activity=>Translucent) TranslucentBlurActivity(App=>Activity=>TranslucentBlur)
源代碼:
com/example/android/apis/app/TranslucentActivity.java com/example/android/apis/app/TranslucentBlurActivity.java
樣式文件:values/styles.xml
透明程序的運行結果如圖2-21所示。

圖2-21 TranslucentActivity和TranslucentBlurActivity程序的運行結果
AndroidManifest.xml中的定義如下所示:
<activity android:name=".app.TranslucentActivity" android:label="@string/activity_translucent" android:theme="@style/Theme.Translucent“ > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter> </activity> <activity android:name=".app.TranslucentBlurActivity" android:label="@string/activity_translucent_blur" android:theme="@style/Theme.Transparent“ > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.SAMPLE_CODE" /> </intent-filter>
</activity>
兩個活動分別使用Theme.Translucent和Theme.Transparent主題,它們都是自定義的主題,內容在values/styles.xml中。
Theme.Translucent主題如下所示:
<style name="Theme.Translucent" parent="android:style/Theme.Translucent"> <item name="android:windowBackground"> @drawable/translucent_background</item> <item name="android:windowNoTitle">true</item> <item name="android:colorForeground">#fff</item> </style>
Theme.Transparent主題如下所示:
<style name="Theme.Transparent"> <item name="android:windowIsTranslucent">true</item> <item name="android:windowAnimationStyle"> @android:style/Animation.Translucent</item> <item name="android:windowBackground"> @drawable/transparent_background</item> <item name="android:windowNoTitle">true</item> <item name="android:colorForeground">#fff</item> </style>
Theme.Transparent實際上是一個沒有繼承預定義主題的主題,在其中自定義了windowIsTranslucent和windowAnimationStyle屬性,取得了和繼承Theme.Translucent類似的效果,并且使用了windowNoTitle表示設置為沒有標題欄。
兩個主題使用的背景數值在colors.xml中定義,如下所示:
<drawable name="translucent_background">#e0000000</drawable> <drawable name="transparent_background">#00000000</drawable>
除此之外,TranslucentBlurActivity之所以能夠獲得背景模糊的效果,是因為在源代碼中進行了進一步的設置,如下所示:
public class TranslucentBlurActivity extends Activity { protected void onCreate(Bundle icicle) { super.onCreate(icicle); getWindow(). // 獲得窗口,用以設置其中的特性 setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND, WindowManager.LayoutParams.FLAG_BLUR_BEHIND); setContentView(R.layout.translucent_background); } }
設置模糊效果是通過窗口管理器設置參數來完成的,這種設置只有在背景設置為透明后才能顯示效果。