天天看點

android自定義控件并添加屬性的方法以及示例

安卓系統為我們提供了豐富的控件,但是在實際項目中我們仍然需要重新通過布局來實作一些效果,比如我們需要一個上面圖示,下面文字的button,類似于下面這樣的:

android自定義控件并添加屬性的方法以及示例

最直接的解決辦法是通過将imageview和textview放在一個垂直排列的linearlayout中,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<code>&lt;linearlayout xmlns:android=</code><code>"http://schemas.android.com/apk/res/android"</code>

<code>    </code><code>android:layout_width=</code><code>"fill_parent"</code>

<code>    </code><code>android:layout_height=</code><code>"fill_parent"</code>

<code>    </code><code>android:gravity=</code><code>"center"</code>

<code>    </code><code>android:orientation=</code><code>"vertical"</code>

<code>&gt;</code>

<code>    </code><code>&lt;imageview</code>

<code>        </code><code>android:id=</code><code>"@+id/icon_part"</code>

<code>        </code><code>android:layout_width=</code><code>"wrap_content"</code>

<code>        </code><code>android:layout_height=</code><code>"wrap_content"</code>

<code>        </code><code>android:layout_gravity=</code><code>"center"</code>

<code>        </code><code>/&gt;</code>

<code>    </code><code>&lt;textview</code>

<code>        </code><code>android:id=</code><code>"@+id/text_part"</code>

<code>        </code><code>android:textcolor=</code><code>"#000000"</code>

<code>/&gt;</code>

<code>&lt;/linearlayout&gt;</code>

但是每一個button都需要這麼長的代碼,上面三個按鈕的話就需要重複寫三次,而且别人一看是個linearlayout,不會将它button聯系起來。

如果有一種辦法能将上面那個布局組合成一個控件就好了。

的确是有辦法的。主要有兩方面的工作。

1.建立一個繼承自linearlayout的類(也可以是其他布局類,不過linearlayout好像比較合适),然後通過inflater在這個類的構造函數中将上面的布局添加進去。

2.為了能在xml中也給這個自定義控件賦予屬性來獲得現實效果,比如字型大小、圖示資源等,我們還需要在attrs檔案中申明一些自定義屬性。你可以查閱declare-styleable了解這是怎麼回事。

我這裡有一個已經實作了這種button效果的類fleximagebutton:

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

<code>package com.jcodecraeer.client.widget;</code>

<code>import com.jcodecraeer.client.r;</code>

<code>import android.content.context;</code>

<code>import android.content.res.typedarray;</code>

<code>import android.graphics.drawable.drawable;</code>

<code>import android.util.attributeset;</code>

<code>import android.view.layoutinflater;</code>

<code>import android.view.view;</code>

<code>import android.widget.imageview;</code>

<code>import android.widget.linearlayout;</code>

<code>import android.widget.textview;</code>

<code>public class fleximagebutton extends linearlayout {</code>

<code>    </code><code>private imageview imageview;</code>

<code>    </code><code>private textview textview;</code>

<code>    </code><code>private charsequence text;</code>

<code>    </code><code>private drawable drawable;</code>

<code>    </code><code>private float textsize;</code>

<code>    </code><code>public fleximagebutton(context context) {</code>

<code>        </code><code>super</code><code>(context);</code>

<code>        </code><code>// todo auto-generated constructor stub</code>

<code>    </code><code>}</code>

<code>    </code><code>public fleximagebutton(context context, attributeset attrs) {</code>

<code>        </code><code>super</code><code>(context, attrs);</code>

<code>        </code><code>typedarray a = context.obtainstyledattributes(attrs, r.styleable.fleximagebutton);</code>

<code>        </code><code>text = a.gettext(r.styleable.fleximagebutton_text);</code>

<code>        </code><code>if</code><code>(text==</code><code>null</code><code>){</code>

<code>            </code><code>text=</code><code>""</code><code>;</code>

<code>        </code><code>}</code>

<code>        </code><code>drawable d = a.getdrawable(r.styleable.fleximagebutton_src);</code>

<code>        </code><code>if</code>

<code>(d !=</code><code>null</code><code>) {</code>

<code>            </code><code>drawable=d;</code>

<code>        </code><code>}</code><code>else</code>

<code>{</code>

<code>            </code><code>throw</code>

<code>new</code> <code>runtimeexception(</code><code>"圖像資源為空"</code><code>);</code>

<code>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                </code> 

<code>        </code><code>textsize = a.getdimension(r.styleable.fleximagebutton_textsize,12);</code>

<code>        </code><code>string infservice = context.layout_inflater_service;</code>

<code>        </code><code>layoutinflater inflater = (layoutinflater) context</code>

<code>                </code><code>.getsystemservice(context.layout_inflater_service);</code>

<code>        </code><code>inflater.inflate(r.layout.flex_image_button_layout,</code><code>this</code><code>);</code>

<code>        </code><code>imageview = (imageview) findviewbyid(r.id.icon_part);</code>

<code>        </code><code>imageview.setimagedrawable(drawable);</code>

<code>        </code><code>textview = (textview) findviewbyid(r.id.text_part);</code>

<code>        </code><code>textview.settextsize((float) textsize);</code>

<code>        </code><code>textview.settext(text);</code>

<code>        </code><code>if</code><code>(text.equals(</code><code>""</code><code>)||text==</code><code>null</code><code>){</code>

<code>            </code><code>textview.setvisibility(view.gone);</code>

<code>        </code><code>a.recycle();</code>

<code>    </code><code>public void setimageresource(int resid) {</code>

<code>        </code><code>imageview.setimageresource(resid);</code>

<code>    </code><code>public void settextviewtext(string text) {</code>

<code>}</code>

在attrs.xml檔案中我們聲明一些自定義屬性,這裡我們希望我的fleximagebutton能擁有可以靈活設定的文字屬性,字型大小屬性、圖示資源屬性,是以我這樣定義:

<code>&lt;resources&gt;</code>

<code>    </code><code>&lt;declare-styleable name=</code><code>"fleximagebutton"</code><code>&gt;</code>

<code>        </code><code>&lt;attr name=</code><code>"text"</code>

<code>format=</code><code>"reference"</code><code>/&gt;</code>

<code>        </code><code>&lt;attr name=</code><code>"src"</code>

<code>        </code><code>&lt;attr name=</code><code>"textsize"</code> 

<code>format=</code><code>"dimension"</code><code>/&gt;</code>

<code>    </code><code>&lt;/declare-styleable&gt;</code>

<code>&lt;/resources&gt;</code>

其中<code>format=</code><code>"reference"</code>表示這個屬性的值類型是資源id,也就是說在使用<code></code>fleximagebutton的時候我隻可以用資源id來為這個屬性指派。屬性值類型有那些,我在文章結尾的附錄裡面一一列出。

上面我們已經完成了一個自定義的控件,activity的布局檔案中如下使用fleximagebutton:

<code>&lt;com.jcodecraeer.client.widget.fleximagebutton</code>

<code>    </code><code>android:layout_height=</code><code>"fill_parent"</code>       

<code>    </code><code>android:layout_width=</code><code>"50dip"</code>

<code>    </code><code>cl:src=</code><code>"@drawable/toolbar_collect"</code>

<code>    </code><code>cl:text=</code><code>"@string/collect"</code>

<code>    </code><code>android:clickable=</code><code>"true"</code>

<code>    </code><code>android:focusable=</code><code>"true"</code>

<code>    </code><code>android:layout_marginleft=</code><code>"5dip"</code>

<code>    </code><code>android:layout_marginright=</code><code>"5dip"</code>

<code>    </code><code>android:contentdescription=</code><code>"收藏"</code>

<code>                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              </code> 

<code>    </code><code>android:background=</code><code>"@drawable/back_selector"</code>

仔細的人會注意到所有這些屬性中,有兩種形式。其中凡是android:開頭的都是系統屬性,而

<code>cl:src=</code><code>"@drawable/toolbar_collect"</code>

<code>cl:text=</code><code>"@string/collect"</code>

為我自定義的屬性,為什麼是cl:開頭?

你也可以不用cl開頭,但是不管你用什麼開頭,如果你用到了自定義屬性,你都必須在activity布局檔案的最開始這樣聲明:

<code>&lt;?xml version=</code><code>"1.0"</code>

<code>encoding=</code><code>"utf-8"</code><code>?&gt;</code>

<code>&lt;relativelayout</code>

<code>    </code><code>xmlns:android=</code><code>"http://schemas.android.com/apk/res/android"</code>

<code>    </code><code>xmlns:cl=</code><code>"http://schemas.android.com/apk/res/com.jcodecraeer.client"</code>

其中<code>cl</code>就是剛剛用到的,<code>com.jcodecraeer.client</code>為我的apk包名,注意是apk包名,而不是你自定義控件的在包中的路徑。

附錄:自定義屬性的值類型:

1. reference:參考某一資源id。

(1)屬性定義:

<code>&lt;declare-styleable name=</code><code>"名稱"</code><code>&gt;</code>

<code>    </code><code>&lt;attr format=</code><code>"reference"</code>

<code>name=</code><code>"background"</code>

<code>&lt;/declare-styleable&gt;</code>

(2)屬性使用:

<code>&lt;imageview</code>

<code>    </code><code>android:layout_width=</code><code>"42dip"</code>

<code>    </code><code>android:layout_height=</code><code>"42dip"</code>

<code>    </code><code>android:background=</code><code>"@drawable/圖檔id"</code>

2. color:顔色值。

<code>    </code><code>&lt;attr format=</code><code>"color"</code>

<code>name=</code><code>"textcolor"</code>

<code>&lt;textview</code>

<code>    </code><code>android:textcolor=</code><code>"#00ff00"</code>

3. boolean:布爾值。

<code>    </code><code>&lt;attr format=</code><code>"boolean"</code>

<code>name=</code><code>"focusable"</code>

<code>&lt;button</code>

4. dimension:尺寸值。

<code>    </code><code>&lt;attr format=</code><code>"dimension"</code>

<code>name=</code><code>"layout_width"</code>

5. float:浮點值。

<code>&lt;declare-styleable name=</code><code>"alphaanimation"</code><code>&gt;</code>

<code>    </code><code>&lt;attr format=</code><code>"float"</code>

<code>name=</code><code>"fromalpha"</code>

<code>name=</code><code>"toalpha"</code>

<code>&lt;alpha</code>

<code>    </code><code>android:fromalpha=</code><code>"1.0"</code>

<code>    </code><code>android:toalpha=</code><code>"0.7"</code>

6. integer:整型值。

<code>&lt;declare-styleable name=</code><code>"animatedrotatedrawable"</code><code>&gt;</code>

<code>    </code><code>&lt;attr format=</code><code>"integer"</code>

<code>name=</code><code>"frameduration"</code>

<code>name=</code><code>"framescount"</code>

<code>&lt;animated-rotate</code>

<code>    </code><code>android:frameduration=</code><code>"100"</code>

<code>    </code><code>android:framescount=</code><code>"12"</code>

<code>     </code><code>/&gt;</code>

7. string:字元串。

<code>&lt;declare-styleable name=</code><code>"mapview"</code><code>&gt;</code>

<code>    </code><code>&lt;attr format=</code><code>"string"</code>

<code>name=</code><code>"apikey"</code>

<code>&lt;com.google.android.maps.mapview</code>

<code>    </code><code>android:apikey=</code><code>"0jokq80od1jl9c6haja99ugxcris2cgjko_bc_g"</code>

8. fraction:百分數。

<code>&lt;declare-styleable name=</code><code>"rotatedrawable"</code><code>&gt;</code>

<code>    </code><code>&lt;attr format=</code><code>"fraction"</code>

<code>name=</code><code>"pivotx"</code>

<code>name=</code><code>"pivoty"</code>

<code>&lt;rotate</code>

<code>    </code><code>android:pivotx=</code><code>"200%"</code>

<code>    </code><code>android:pivoty=</code><code>"300%"</code>

<code>    </code><code>/&gt;</code>

9. enum:枚舉值。

<code>    </code><code>&lt;attr name=</code><code>"orientation"</code><code>&gt;</code>

<code>        </code><code>&lt;enum name=</code><code>"horizontal"</code>

<code>value=</code><code>"0"</code>

<code>        </code><code>&lt;enum name=</code><code>"vertical"</code>

<code>value=</code><code>"1"</code>

<code>    </code><code>&lt;/attr&gt;</code>

<code>&lt;linearlayout</code>

10. flag:位或運算。

<code>    </code><code>&lt;attr name=</code><code>"windowsoftinputmode"</code><code>&gt;</code>

<code>        </code><code>&lt;flag name=</code><code>"stateunspecified"</code>

<code>        </code><code>&lt;flag name=</code><code>"stateunchanged"</code>

<code>        </code><code>&lt;flag name=</code><code>"statehidden"</code>

<code>value=</code><code>"2"</code>

<code>        </code><code>&lt;flag name=</code><code>"statealwayshidden"</code>

<code>value=</code><code>"3"</code>

<code>        </code><code>&lt;flag name=</code><code>"statevisible"</code>

<code>value=</code><code>"4"</code>

<code>        </code><code>&lt;flag name=</code><code>"statealwaysvisible"</code>

<code>value=</code><code>"5"</code>

<code>        </code><code>&lt;flag name=</code><code>"adjustunspecified"</code>

<code>value=</code><code>"0x00"</code>

<code>        </code><code>&lt;flag name=</code><code>"adjustresize"</code>

<code>value=</code><code>"0x10"</code>

<code>        </code><code>&lt;flag name=</code><code>"adjustpan"</code>

<code>value=</code><code>"0x20"</code>

<code>        </code><code>&lt;flag name=</code><code>"adjustnothing"</code>

<code>value=</code><code>"0x30"</code>

<code>&lt;activity</code>

<code>    </code><code>android:windowsoftinputmode=</code><code>"stateunspecified | stateunchanged | statehidden"</code> <code>&gt;</code>

<code>&lt;/activity&gt;</code>

注意:屬性定義時可以指定多種類型值:

<code>    </code><code>&lt;attr format=</code><code>"reference|color"</code>

<code>    </code><code>android:background=</code><code>"@drawable/圖檔id|#00ff00"</code>

<code></code>

繼續閱讀