Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中自定義樣式與View的構造函數中的第三個參數defStyle的意義

Android中自定義樣式與View的構造函數中的第三個參數defStyle的意義

編輯:關於Android編程

零、序   一、自定義Style   二、在XML中為屬性聲明屬性值     1. 在layout中定義屬性     2. 設置Style     3. 通過Theme指定   三、在運行時獲取屬性值     1. View的第三個構造函數的第三個參數defStyle     2. obtailStyledAttributes     3. Example   四、結論與代碼下載   零、序     系統自帶的View可以在xml中配置屬性,對於寫的好的Custom View同樣可以在xml中配置屬性,為了使自定義的View的屬性可以在xml中配置,需要以下4個步驟:   通過<declare-styleable>為自定義View添加屬性   在xml中為相應的屬性聲明屬性值   在運行時(一般為構造函數)獲取屬性值   將獲取到的屬性值應用到View     怎麼將獲取到的屬性值應用到View就不用說了,自己定義的屬性什麼用處自己肯定是清楚的,所以接下來看一下前三點。   一、自定義Style     通過<declare-styleable>元素聲明Custom View需要的屬性即可,下面是一個例子,文件是res/values/attrs.xml     <?xml version="1.0" encoding="utf-8"?> <resources>     <declare-styleable name="Customize">         <attr name="attr_one" format="string" />         <attr name="attr_two" format="string" />         <attr name="attr_three" format="string" />         <attr name="attr_four" format="string" />     </declare-styleable>       <attr name="CustomizeStyle" format="reference" /> </resources>     在上述xml中,我們聲明了Customize與CustomizeSyle,Customize包含了attr_one、attr_two、attr_three與attr_four四個attribute,CustomizeStyle也是一個attribute,但是卻沒有聲明在declare-styleable中。     定義在declare-styleable中與直接用attr定義沒有實質的不同,上述xml中,無論attr_one - attr_four是否聲明在declare-styleable中,系統都會為我們在R.attr中生成5個attribute     public static final class attr {     public static final int CustomizeStyle=0x7f010004;     public static final int attr_one=0x7f010000;     public static final int attr_two=0x7f010001;     public static final int attr_three=0x7f010002;     public static final int attr_four=0x7f010003; }     不同的是,如果聲明在declare-styleable中,系統還會為我們在R.styleable中生成相關的屬性。     public static final class styleable {     public static final int[] Customize = {         0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003     };     public static final int Customize_attr_one = 0;     public static final int Customize_attr_two = 1;         public static final int Customize_attr_three = 2;     public static final int Customize_attr_four = 3; } 復制代碼    如上所示,R.styleable.Customize是一個int[],而裡面的元素的值正好和R.attr.attr_one - R.attr.attr_four一一對應,而R.styleable.Customize_attr_one等4個值就是R.attr.attr_one-R.attr.attr_four在R.styleable.Customize數組中的索引。這個數組和索引在第三步運行時獲得屬性值時會用到,將attr分組聲明在declare-styleabe中的作用就是系統會自動為我們生成這些東西,如果不聲明在declare-styleable中,我們完全可以在需要的時候自己構建這個數組,由於數組是自己構建的,每個屬性的下標索引也就很清楚了,只是比較麻煩。以上一家之言,不過從使用及實驗難上看確實是這樣的。   二、在xml中為相應的屬性聲明屬性值           我們知道,在xml中為屬性賦值有幾種不同的方式   直接在layout中使用屬性   設置style並在style中設置屬性   Application和Activity可以指定theme,可以在theme中指定在當前Application或Activity中屬性的默認值           下面就分別看一下這三種方式   1. 直接在layout中使用屬性         在xml layout中使用自定義屬性和使用系統屬性差不多,不過屬性所屬的namespace不同,比如像下面這樣。     <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:ad="http://schemas.android.com/apk/res/com.angeldevil.customstyle"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".MainActivity" >       <com.angeldevil.customstyle.CustomTextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         ad:attr_one="attr one in xml"         style="@style/ThroughStyle"         android:text="@string/hello_world" />   </RelativeLayout>     像layout_width等屬性屬於android的namespace,自定義的屬性屬於當前程序的namespace,只需像聲明android的namespace一樣聲明當前程序的namespace就好,只需要把上面紅色部分的android換成當前程序的包名。應用屬性的時候也需要注意屬性的namespace。   2. 設置style並在style中設置屬性   看上面xml中綠色的那一行,我們為CustomTextView聲明了一個style:ThroughStyle,這個Style很簡單,只是指定了兩個屬性的值   <style name="ThroughStyle">     <item name="attr_one">attr one from style</item>     <item name="attr_two">attr two from style</item> </style>   注意,在style中我們聲明了attr_one的值,同時在xml中也直接向attr_one賦了值,最終用哪一個有個優先級的問題,後面在第三節:在運行時獲取屬性值中再說,接下來看下第三種方式。   3. theme中指定在當前Application或Activity中屬性的默認值   <!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme">     <!-- All customizations that are NOT specific to a particular API-level can go here. -->     <item name="attr_one">attr one from theme</item>     <item name="attr_two">attr two from theme</item>     <item name="attr_three">attr three from theme</item>     <item name="CustomizeStyle">@style/CustomizeStyleInTheme</item> </style>   <style name="CustomizeStyleInTheme">     <item name="attr_one">attr one from theme reference</item>     <item name="attr_two">attr two from theme reference</item>     <item name="attr_three">attr three from theme reference</item> </style>      在上述xml中,我們在AppTheme中為attr_one、attr_two與attr_three指定了值,但是同時也為CustomizeStyle指定了一個reference,而在這個reference中為attr_one、attr_two與attr_three指定了值,CustomizeStyle就是我們在attrs.xml中定義的一個屬性。在theme中為屬性設置值的方式有兩這種,直接在theme中定義或通過另一個attribute引用一個style,這兩種方式還是有區別的,在下面的獲取屬性值一節中可以看到。   三、在運行時獲取屬性值           在styles.xml中,我們同時定義一個DefaultCustomizeStyle的style,它的作用等下可以看到。   <style name="DefaultCustomizeStyle">     <item name="attr_one">attr one from defalut style res</item>     <item name="attr_two">attr two from defalut style res</item>     <item name="attr_three">attr three from defalut style res</item> </style>   先看下CustomTextView的代碼     public class CustomTextView extends TextView {     private static final String TAG = CustomTextView.class.getSimpleName();       public CustomTextView(Context context) {         super(context);     }       public CustomTextView(Context context, AttributeSet attrs) {         this(context, attrs, R.attr.CustomizeStyle);     }       public CustomTextView(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Customize, defStyle, R.style.DefaultCustomizeStyle);         String one = a.getString(R.styleable.Customize_attr_one);         String two = a.getString(R.styleable.Customize_attr_two);         String three = a.getString(R.styleable.Customize_attr_three);         String four = a.getString(R.styleable.Customize_attr_four);         Log.i(TAG, "one:" + one);         Log.i(TAG, "two:" + two);         Log.i(TAG, "three:" + three);         Log.i(TAG, "four:" + four);         a.recycle();     } }      主要代碼都在第三個函數中,這裡也沒做什麼,只是通過Context的obtainStyledAttributes獲得了前面定義的4個屬性的值並打印了出來。   View的第三個構造函數的第三個參數defStyle   如果在Code中實例化一個View會調用第一個構造函數,如果在xml中定義會調用第二個構造函數,而第三個函數系統是不調用的,要由View(我們自定義的或系統預定義的View,如此處的CustomTextView和Button)顯式調用,比如在這裡我們在第二個構造函數中調用了第三個構造函數,並將R.attr.CustomizeStyle傳給了第三個參數。     第三個參數的意義就如同它的名字所說的,是默認的Style,只是這裡沒有說清楚,這裡的默認的Style是指它在當前Application或Activity所用的Theme中的默認Style,以系統中的Button為例說明。     public Button(Context context) {     this(context, null); }   public Button(Context context, AttributeSet attrs) {     this(context, attrs, com.android.internal.R.attr.buttonStyle); }   public Button(Context context, AttributeSet attrs, int defStyle) {     super(context, attrs, defStyle); }      在Code中實例化View會調用第一個構造函數,在XML中定義會調用第二個構造函數,在Button的實現中都調用了第三個構造函數,並且defStyle的值是com.android.internal.R.attr.buttonStyle。buttonStyle是系統中定義的一個attribute,系統默認有一個Theme,比如4.0中是Theme.Holo   <style name="Theme.DeviceDefault" parent="Theme.Holo" >     ...     <item name="buttonStyle">@android:style/Widget.DeviceDefault.Button</item>     .... </style>   上面是系統默認的Theme,為buttonStyle指定了一個Style     <style name="Widget.DeviceDefault.Button" parent="Widget.Holo.Button" > </style>   <style name="Widget.Holo.Button" parent="Widget.Button"> <item name="android:background">@android:drawable/btn_default_holo_dark</item>     <item name="android:textAppearance">?android:attr/textAppearanceMedium</item>     <item name="android:textColor">@android:color/primary_text_holo_dark</item>     <item name="android:minHeight">48dip</item>     <item name="android:minWidth">64dip</item> </style> 復制代碼    這個Style定義了系統中Button的默認屬性,如background等。     從文檔中第三個構造函數的說明中也可以看到,這個構造函數的作用是View的子類提供這個類的基礎樣式   View(Context context, AttributeSet attrs, int defStyleAttr)   Perform inflation from XML and apply a class-specific base style.     上面說的都比較抽象,還是直接看實例代碼來的清楚明白,實驗用的代碼上面全都貼完了,這裡直接看結果,但在這之前要先看一個函數:obtainStyledAtributes。   obtainStyledAtributes   我們要獲取的屬性值都是通過這個函數返回的TypedArray獲得的,這是官方說明:obtainStyledAttributes,以下是函數原型:   public TypedArray obtainStyledAttributes (AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes)   4個參數的意思分別是:       set:屬性值的集合       attrs:我們要獲取的屬性的資源ID的一個數組,如同ContextProvider中請求數據庫時的Projection數組,就是從一堆屬性中我們希望查詢什麼屬性的值       defStyleAttr:這個是當前Theme中的一個attribute,是指向style的一個引用,當在layout xml中和style中都沒有為View指定屬性時,會從Theme中這個attribute指向的Style中查找相應的屬性值,這就是defStyle的意思,如果沒有指定屬性值,就用這個值,所以是默認值,但這個attribute要在Theme中指定,且是指向一個Style的引用,如果這個參數傳入0表示不向Theme中搜索默認值       defStyleRes:這個也是指向一個Style的資源ID,但是僅在defStyleAttr為0或defStyleAttr不為0但Theme中沒有為defStyleAttr屬性賦值時起作用     鏈接中對這個函數說明勉強過得去,這裡簡要概括一下。對於一個屬性可以在多個地方指定它的值,如XML直接定義,style,Theme,而這些位置定義的值有一個優先級,按優先級從高到低依次是:   直接在XML中定義>style定義>由defStyleAttr和defStyleRes指定的默認值>直接在Theme中指定的值     看這個關系式就比較明白了,defStyleAttr和defStyleRes在前面的參數說明中已經說了,“直接在Theme中指定的值”的意思在下面的示代碼中可以看到。   實驗驗證   相關的代碼都前面都已經貼上了,不過為了方便查看,這裡再把相關的XML一起貼一遍     main_activity.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:ad="http://schemas.android.com/apk/res/com.angeldevil.customstyle"     xmlns:tools="http://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".MainActivity" >       <com.angeldevil.customstyle.CustomTextView         android:layout_width="wrap_content"         android:layout_height="wrap_content"         ad:attr_one="attr one in xml"         style="@style/ThroughStyle"         android:text="@string/hello_world" />   </RelativeLayout>   attrs.xml <?xml version="1.0" encoding="utf-8"?> <resources>       <declare-styleable name="Customize">         <attr name="attr_one" format="string" />         <attr name="attr_two" format="string" />         <attr name="attr_three" format="string" />         <attr name="attr_four" format="string" />     </declare-styleable>       <attr name="CustomizeStyle" format="reference" />   </resources>   styles.xml <resources>       <style name="AppBaseTheme" parent="android:Theme.Light">     </style>     <!-- Application theme. -->     <style name="AppTheme" parent="AppBaseTheme">         <!-- All customizations that are NOT specific to a particular API-level can go here. -->         <item name="attr_one">attr one from theme</item>         <item name="attr_two">attr two from theme</item>         <item name="attr_three">attr three from theme</item>         <item name="CustomizeStyle">@style/CustomizeStyleInTheme</item>     </style>       <style name="CustomizeStyleInTheme">         <item name="attr_one">attr one from theme reference</item>         <item name="attr_two">attr two from theme reference</item>         <item name="attr_three">attr three from theme reference</item>     </style>       <style name="ThroughStyle">         <item name="attr_one">attr one from style</item>         <item name="attr_two">attr two from style</item>     </style>          <style name="DefaultCustomizeStyle">         <item name="attr_one">attr one from defalut style res</item>         <item name="attr_two">attr two from defalut style res</item>         <item name="attr_three">attr three from defalut style res</item>     </style>   </resources>
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved