天天看点

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>

继续阅读