Android自定義屬性及xmlns解析
寫在前面
halo,大家好~又到了每週一次的分享時間(放屁!),每天從出門到上班大約有四十多分鐘的公交,也利用這段時間刷刷別人的技術部落格,成長了很多,這周重新溫習了一下Android自定義View和屬性,在這個過程中,對下列xml佈局中的語法產生了好奇:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" >
xmlns幾乎在每一個xml檔案最外層控制元件都有,但是它有什麼作用呢?於是乎便有了想寫這篇部落格的衝動。
因此,本文的重點內容就是簡單闡述一下如何自定義View和它的屬性,並且再來講講xmlns的用途。
自定義View
眾所周知,View和ViewGroup承載著Android檢視的任務,並且ViewGroup繼承自View,Google為了降低開發者的入門門檻,提供了很多已經封裝好了的View控制元件,比如Button、TextView、ImageView等等,對於ViewGroup來說,也有LinearLayout、FrameLayout、RelativeLayout等能夠包含其他View的組控制元件。
無論哪一種控制元件,它都直接或者間接地繼承自View類,雖然Google所提供的控制元件非常豐富,但是在實際的專案中,往往需要自己去特定一些View控制元件,終歸有以下四種情況:
1. 繼承View
2. 繼承ViewGroup
3. 繼承已有的View
4. 繼承已有的ViewGroup
本文主要講述第一種情況,至於後面三種情況,就需要深入到View的繪製流程之中學習,萬變不離其宗。
onMeasure
onLayout
onDraw
這三座大山是View繪製的精髓,文章暫時不涉及View的繪製;如果只是建立一個普通的自定義View,則只用關心onDraw方法的重寫,還是直接依照步驟上程式碼看看吧:
建立MyView的建構函式:
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, @Nullable AttributeSet attrs) {
this (context, attrs, 0);
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);
s = typedArray.getString(R.styleable.MyView_Text);
typedArray.recycle();
}
建構函式可以當成模板使用,其中看到有三個引數的建構函式的情況有些複雜,什麼是TypeArray?可以理解成xml佈局中屬性的集合,在自定義屬性中,也是通過這個物件來獲取我們需要的自定義值。
context.obtainStyledAttributes()
方法接受四個引數,其中我們關心的是第二個引數,它是一個id值,
構成方法是:
R.styleable.XXX
建立自定義屬性類別
R.styleable.XXX就是我們需要自己定義的屬類別性,在res/values/中新建attrs.xml檔案,並新增以下程式碼:
<resources>
<declare-styleable name="MyView">
<attr name="Text" format="string"/>
<attr name="TextColor" format="color"/>
<attr name="TextDrawable" format="reference"/>
<attr name="TextSize" format="integer"/>
<attr name="TextAllow" format="boolean"/>
</declare-styleable>
</resources>
標籤包裹自定義的屬性類別,也就是上文中XXX所需要替代的值,在該標籤下可以包含多個標籤值,每一個attr都代表能夠包含的屬性,而name表示的是xml中自定義的屬性名,format表示該屬性的取值型別,可以包含string、integer、boolean、color、refrence等,分別表示字串、int值、布林值、顏色id、物件引用(drawable等)。
xml中新增自定義屬性
我們在xml中為自定義View新增自定義屬性,可以如下所示:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".activities.ViewActivity">
<com.yourzeromax.test_new.views.MyView
android:id="@+id/mv_test"
android:layout_width="40dp"
android:layout_height="40dp"
app:Text="123"
app:TextAllow="true"
app:TextColor="@color/colorAccent"
app:TextSize="13"
app:TextDrawable="@drawable/drable_list"/>
</LinearLayout>
我們再回來看一下View的建構函式中的程式碼:
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MyView, defStyleAttr, 0);
String s = typedArray.getString(R.styleable.MyView_Text);
typedArray.recycle();
其中s的值便是我們在xml中指定的字串值,在本例子中,s=”123”,這樣便完成了xml屬性到程式碼屬性的轉換,不信可以自己試試。
Tips:在使用完TyoedArray物件以後,一定要記得recycle()回收,避免記憶體洩漏的發生。
xmlns的作用
xml佈局中使用最多的是android:id、andorid:layout_width等形式,在我們自定義的xml中,添加了app:Text、app:TextAllow等這樣的寫法,其實冒號前面的單詞並不重要,重要的是後面引號中的內容,前面的單詞可以任意取名,我們在最開始指定了這樣一句程式碼:
xmlns:app="http://schemas.android.com/apk/res-auto"
包括系統自動為我們新增的這一句程式碼:
xmlns:android="http://schemas.android.com/apk/res/android"
正是這兩句程式碼的存在,才使得我們能夠使用android、app這樣的標籤,為什麼呢?
xmlns是xml namespace的縮寫形式,換言之,這條程式碼就是為我們指定了app或者android的名稱空間,一般情況下,我們引用“apk/res-auto”就讓app能夠訪問res下所有資源的能力,當然如果想讓其只能訪問某個res資源,只需要引用“包名/apk/res/具體屬性資料夾”即可。有了這些語句,就能夠讓我們使用已經制定好的屬性集,懂了吧?是不是特別簡單
xmlns:tools的用法
在佈局中,任意xml標籤下新增程式碼:
xmlns:tools="http://schemas.android.com/tools"
之後,我們便能使用android為我們提供的tools,先舉個開發過程中的案例:
有時候在佈局一個xml的過程中需要檢視某個TextView的文字效果,於是指定了android:Text =
“客戶們都是笨蛋”;這時,產品上線,結果忘了刪除這行程式碼,資料載入也沒有重新設定text內容。
這種場面是不是就很尷尬了?使用tools標籤就能夠避免這樣的尷尬,我們在xml佈局中加入tools:text=”客戶們都是笨蛋”,發現預覽中是這樣的:
但實際上,如果執行的話,是看不到這條text的。
除此之外,tools:標籤幾乎支援所有android:的同名標籤,比如tools:src、tools:textSize等,可以自己進行探索。
總之,tools的作用就是能夠方便開發者在開發過程中提前預覽xml佈局而對之後的執行結果不產生影響,挺方便的一個工具。
歡迎關注我的部落格