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