【Android XML】Android XML 轉 Java Code 系列之 style(3),androidxml
最近一個月把代碼重構了一遍, 感覺舒服多了, 但總體開發進度沒有變化.. 今天聊聊把style屬性轉換成Java代碼的辦法
先說結論: 引用系統style是無法完美的實現的, 我們如果有寫成Java代碼的需求, 請盡量避免使用系統style. 自訂style沒問題.
style是什麼?
(參考連結) http://developer.android.com/guide/topics/resources/style-resource.html
" A style resource defines the format and look for a UI. A style can be applied to an individual View (from within a layout file) or to an entireActivity or application (from within the manifest file)."
更通俗的理解是, style其實是放置一組attribute的宏, 在控制項中指定這個style, 將在xml解析時將style的一組屬性應用到該控制項中. 舉個栗子:
這裡有個style, 定義在res/value中:
<?xml version="1.0" encoding="utf-8"?><resources> <style name="CustomText" parent="@style/Text"> <item name="android:textSize">20sp</item> <item name="android:textColor">#008</item> </style></resources>
然後我們在layout中的某個控制項引用了這個style:
<?xml version="1.0" encoding="utf-8"?><EditText style="@style/CustomText" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, World!" />
實際上, 他是等於:
<?xml version="1.0" encoding="utf-8"?><EditText android:textSize="20sp" android:textColor="#008" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Hello, World!" />
有點宏替換的味道, 如果接觸過html的同學可以很容易想到CSS這種東西, 兩個想要做的基本是一樣的.
需要指明的是: style的屬性的優先順序是最低的, 會被控制項的其他相同屬性覆蓋掉. 這是理所當然的, 不然控制項裡的attribute要不服了(你都把我寫出來了, 居然和我說我沒用, 要被style那貨覆蓋掉?!)
讓我們再回到這個被我們定義的style上, 會發現他還有一個叫parent的屬性. 這裡我們用物件導向的父類來理解, 就是子style會繼承父類的屬性. 同樣的, 父類的屬性要比子類屬性優先順序要低. (你都把我寫出來了, 居然和我說我沒用, 要被老爸的style覆蓋掉?!)
style不是什麼?
style不屬於android Namespace中的屬性 (不以android:開頭), 沒有對應的setStyle方法可以使用, 我的理解是它屬於xml預先載入的一種"機制".
自訂style的翻譯:
那麼對於自訂的style, 翻譯就很簡單了.
對於一個style, 將其替換成style中的attribute集合, 並向上 (父類) 繼續增加父類集合, 並注意優先順序 (子類可以覆蓋父類attribute).
系統style的翻譯:
系統style的翻譯主要存在兩個問題:
1. 系統style是內建在系統內部的, 不同的系統style並不一樣, 特別是深度定製化的如MIUI, Flyme等作業系統. 如果只是使用一些簡單的比較標準的style, 如progressbar等, 可以通過SDK Manager下載最新Android版本的API, 然後在路徑platforms\android-20\data\res\values中找到標準的系統style, 或直接下載ASOP(路徑framework/base/core/res/res/values/styles.xml. (我在項目中用到的是4.4的style檔案, 5.0的sytle檔案分成了多個, 而且裡面的命名有點不規範)
有些同學會發現, 如progressbar裡面的style: android:attr/progressBarStyleSmall, 是用android:attr索引的. android:attr其實是在theme中定義的屬性, apk的theme在AndroidManifest.xml中定義. 在解析xml過程中, 遇到android:attr的時候, 他就會在apk指定的theme中找到相應的item. 這個item對應的值就是style的值, 如:
style=?android:attr/progressBarStyleSmall對應 最基本的Theme中的<item name="progressBarStyleSmall">@android:style/Widget.ProgressBar.Small</item>
然後你再去styles.xml中尋找Widget.ProgressBar.Small. (這裡還有個要注意的是, 就是系統的style不會聲明parent屬性, 但是以點"."做層級, 比如這裡的Widget.ProgressBar.Small父類是Widget.ProgressBar)
這樣帶來的另一個問題, 深度定製的作業系統各種主題也會有改動, 這樣造成更大的偏差.
2. 系統style用到的資源, 有些是我們從外部無法擷取的. 還是舉Widget.ProgressBar.Small的例子:
<style name="Widget.ProgressBar.Small"> <item name="android:indeterminateDrawable">@android:drawable/progress_small_white</item> <item name="android:minWidth">16dip</item> <item name="android:maxWidth">16dip</item> <item name="android:minHeight">16dip</item> <item name="android:maxHeight">16dip</item> </style>
他裡面用到了@android:drawable/progress_small_white這個系統資源, 但是這個資源不是public的, 我們實現的時候沒辦法把這個資源調用出來. 有些同學會想到反射, 但反射也是不行的. 因為所有的系統資源在ASOP編譯的時候會產生類似於R.java這樣的資源索引檔案, 這些檔案用於我們使用系統資源的id來調用系統資源. 而非public是不會聲明出來的, 也就是說你連id都無法知道, 也就無法擷取對應資源了. 我曾大致閱讀了一下xml的解析實現, 發現到最後都進入了native層, 在native層用c/c++實現, 這讓我望code興歎..
不過ProgressBar的各種樣式應該可以通過api來設定出來, 這個我還沒證實. 可以參考: [Android執行個體] Android 在Java代碼中設定style屬性--使用代碼建立ProgressBar對象
對這個非public系統資源擷取有經驗的同學歡迎交流.
項目代碼:
我在項目中實現了構建style元素, 使用style元素替換為attritutes, 以及style元素之間的關係, 包括對theme的android:attr尋找:
https://github.com/SickWorm/AndroidXMLToJava/blob/master/src/com/excelsecu/androidx2j/AX2JStyle.java
著作權,轉載請註明出處:
http://www.cnblogs.com/sickworm/p/4355396.html