閱讀986 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:orientation="vertical" >
    <ImageView
        android:id="@+id/icon_part"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        />
    <TextView
        android:id="@+id/text_part"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:textColor="#000000" />
</LinearLayout>

但是每一個button都需要這麼長的代碼,上麵三個按鈕的話就需要重複寫三次,而且別人一看是個LinearLayout,不會將它button聯係起來。

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

的確是有辦法的。主要有兩方麵的工作。

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

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


我這裏有一個已經實現了這種button效果的類FlexImageButton:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
package com.jcodecraeer.client.widget;
import com.jcodecraeer.client.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class FlexImageButton extends LinearLayout {
    private ImageView imageView;
    private TextView textView;
    private CharSequence text;
    private Drawable drawable;
    private float textSize;
    public FlexImageButton(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }
    public FlexImageButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlexImageButton);
        text = a.getText(R.styleable.FlexImageButton_text);
        if(text==null){
            text="";
        }
        Drawable d = a.getDrawable(R.styleable.FlexImageButton_src);
        if (d != null) {
            drawable=d;
        } else {
            throw new RuntimeException("圖像資源為空");
        }
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
        textSize = a.getDimension(R.styleable.FlexImageButton_textSize,12);
        String infService = Context.LAYOUT_INFLATER_SERVICE;
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.flex_image_button_layout, this);
        imageView = (ImageView) findViewById(R.id.icon_part);
        imageView.setImageDrawable(drawable);
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 
        textView = (TextView) findViewById(R.id.text_part);
        textView.setTextSize((float) textSize);
        textView.setText(text);
        if(text.equals("")||text==null){
            textView.setVisibility(View.GONE);
        }
        a.recycle();
    }
    public void setImageResource(int resId) {
        imageView.setImageResource(resId);
    }
    public void setTextViewText(String text) {
        textView.setText(text);
    }
}


在attrs.xml文件中我們聲明一些自定義屬性,這裏我們希望我的FlexImageButton能擁有可以靈活設置的文字屬性,字體大小屬性、圖標資源屬性,因此我這樣定義:

1
2
3
4
5
6
7
<resources>
    <declare-styleable name="FlexImageButton">
        <attr name="text" format="reference"/>
        <attr name="src" format="reference"/>
        <attr name="textSize"  format="dimension"/>
    </declare-styleable>
</resources>


其中format="reference"表示這個屬性的值類型是資源id,也就是說在使用FlexImageButton的時候我隻可以用資源id來為這個屬性賦值。屬性值類型有那些,我在文章結尾的附錄裏麵一一列出。



上麵我們已經完成了一個自定義的控件,activity的布局文件中如下使用FlexImageButton:

1
2
3
4
5
6
7
8
9
10
11
12
13
<com.jcodecraeer.client.widget.FlexImageButton
    android:layout_height="fill_parent"       
    android:layout_width="50dip"
    cl:src="@drawable/toolbar_collect"
    cl:text="@string/collect"
    android:clickable="true"
    android:focusable="true"
    android:layout_marginLeft="5dip"
    android:layout_marginRight="5dip"
    android:contentDescription="收藏"
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
    android:background="@drawable/back_selector"
/>

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

1
2
cl:src="@drawable/toolbar_collect"
cl:text="@string/collect"

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

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

1
2
3
4
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout

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


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

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

(1)屬性定義:

1
2
3
<declare-styleable name="名稱">
    <attr format="reference" name="background" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<ImageView
    android:layout_width="42dip"
    android:layout_height="42dip"
    android:background="@drawable/圖片ID" />

2. color:顏色值。

(1)屬性定義:

1
2
3
<declare-styleable name="名稱">
    <attr format="color" name="textColor" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<TextView
    android:layout_width="42dip"
    android:layout_height="42dip"
    android:textColor="#00FF00" />

3. boolean:布爾值。

(1)屬性定義:

1
2
3
<declare-styleable name="名稱">
    <attr format="boolean" name="focusable" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<Button
    android:layout_width="42dip"
    android:layout_height="42dip"
    android:focusable="true" />

4. dimension:尺寸值。

(1)屬性定義:

1
2
3
<declare-styleable name="名稱">
    <attr format="dimension" name="layout_width" />
</declare-styleable>

(2)屬性使用:

1
2
3
<Button
    android:layout_width="42dip"
    android:layout_height="42dip" />

5. float:浮點值。

(1)屬性定義:

1
2
3
4
<declare-styleable name="AlphaAnimation">
    <attr format="float" name="fromAlpha" />
    <attr format="float" name="toAlpha" />
</declare-styleable>

(2)屬性使用:

1
2
3
<alpha
    android:fromAlpha="1.0"
    android:toAlpha="0.7" />

6. integer:整型值。

(1)屬性定義:

1
2
3
4
<declare-styleable name="AnimatedRotateDrawable">
    <attr format="integer" name="frameDuration" />
    <attr format="integer" name="framesCount" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<animated-rotate
    android:frameDuration="100"
    android:framesCount="12"
     />

7. string:字符串。

(1)屬性定義:

1
2
3
<declare-styleable name="MapView">
    <attr format="string" name="apiKey" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<com.google.android.maps.MapView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:apiKey="0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g" />

8. fraction:百分數。

(1)屬性定義:

1
2
3
4
<declare-styleable name="RotateDrawable">
    <attr format="fraction" name="pivotX" />
    <attr format="fraction" name="pivotY" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<rotate
    android:pivotX="200%"
    android:pivotY="300%"
    />

9. enum:枚舉值。

(1)屬性定義:

1
2
3
4
5
6
<declare-styleable name="名稱">
    <attr name="orientation">
        <enum name="horizontal" value="0" />
        <enum name="vertical" value="1" />
    </attr>
</declare-styleable>

(2)屬性使用:

1
2
3
<LinearLayout
    android:orientation="vertical" >
</LinearLayout>

10. flag:位或運算。

(1)屬性定義:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<declare-styleable name="名稱">
    <attr name="windowSoftInputMode">
        <flag name="stateUnspecified" value="0" />
        <flag name="stateUnchanged" value="1" />
        <flag name="stateHidden" value="2" />
        <flag name="stateAlwaysHidden" value="3" />
        <flag name="stateVisible" value="4" />
        <flag name="stateAlwaysVisible" value="5" />
        <flag name="adjustUnspecified" value="0x00" />
        <flag name="adjustResize" value="0x10" />
        <flag name="adjustPan" value="0x20" />
        <flag name="adjustNothing" value="0x30" />
    </attr>
</declare-styleable>

(2)屬性使用:

1
2
3
<activity
    android:windowSoftInputMode="stateUnspecified | stateUnchanged | stateHidden" >
</activity>

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

(1)屬性定義:

1
2
3
<declare-styleable name="名稱">
    <attr format="reference|color" name="background" />
</declare-styleable>

(2)屬性使用:

1
2
3
4
<ImageView
    android:layout_width="42dip"
    android:layout_height="42dip"
    android:background="@drawable/圖片ID|#00FF00" />

最後更新:2017-04-03 12:55:25

  上一篇:go 異步圖片加載、內存、磁盤緩存
  下一篇:go clock_nanosleep避免過度睡眠