Android中自定義控件的情況非常多,一般自定義控件可以分爲兩種:繼承控件及組合控件。前者是通過繼承View或其子類,重寫方法實現自定義的顯示及事件處理方式;後者是通過組合已有的控件,來實現結構的簡化和代碼的重用。
本篇文章主要介紹自定義組合控件,繼承控件後續有機會再述。
自定義組合控件一般來說都是以ViewGroup及其子類(LinearLayout、RelativeLayout、FrameLayout等)爲主,內部嵌套其他控件,來組合成一個新的控件,實現一些特定的需要,可以是代碼簡化,結構清晰,重用性較高。
通常來說,我們會實現定義好一個Layout.xml文件,然後讓我們的自定義控件去加載此xml,並獲取子控件,然後設置屬性(可以通過代碼,也可以從資源文件中加載)、添加事件。
自定義要點:1.加載xml文件是在構造方法中完成的,通過調用inflate(R.layout.my_layout, this , true ),注意第二個和第三個參數;
2.如果需要從資源文件中加載自定義的屬性,則必須 重寫Constructor(Context context, AttributeSet attrs) 此構造方法,屬性是定義在attrs.xml中的;
3.獲取子控件對象,可以在構造方法中獲取,也可以 重寫onFinishInflate()方法 來獲取,個人建議採用第二種,可以保證控件已經完全加載好了。
4.添加事件可以直接在控件中寫,不過考慮到擴展性及複用性,建議對外暴露接口。
示例代碼(代碼比較簡單,只是描述一下思路)
自定義控件layout:header.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<? xml
version = "1.0"
encoding = "utf-8" ?> android:layout_width = "match_parent" android:layout_height = "wrap_content" > < ImageButton
android:id = "@+id/ib_header" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_alignParentRight = "true" android:layout_centerVertical = "true" android:src = "@android:drawable/ic_menu_zoom"
/> < TextView
android:id = "@+id/tv_header" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_centerInParent = "true"
/> </ RelativeLayout > |
自定義控件類:Header.java
01
02
03
04
05
06
07
08
09
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
package
com.ivan.app1.widgets; import
com.ivan.app1.R; import
android.content.Context; import
android.content.res.TypedArray; import
android.graphics.Color; import
android.text.TextUtils; import
android.util.AttributeSet; import
android.view.LayoutInflater; import
android.widget.ImageButton; import
android.widget.LinearLayout; import
android.widget.TextView; /** *
自定義標題欄組合控件,內部包含一個TextView和一個ImageButton *
User: xyh *
Date: 2015/6/2 *
Time: 9:39 */ public
class
Header extends
RelativeLayout { private
TextView mTextView; private
ImageButton mImageButton; private
String titleText; private
int
titleTextColor; private
float
titleTextSize; public
Header(Context context) { super (context); } public
Header(Context context, AttributeSet attrs) { super (context,
attrs); //加載視圖的佈局 LayoutInflater.from(context).inflate(R.layout.header, this , true ); //加載自定義的屬性 TypedArray
a=context.obtainStyledAttributes(attrs,R.styleable.Header); titleText=a.getString(R.styleable.Header_titleText); titleTextColor=a.getColor(R.styleable.Header_titleTextColor,
Color.WHITE); titleTextSize=a.getDimension(R.styleable.Header_titleTextSize,20f); //回收資源,這一句必須調用 a.recycle(); } /** *
此方法會在所有的控件都從xml文件中加載完成後調用 */ @Override protected
void
onFinishInflate() { super .onFinishInflate(); //獲取子控件 mTextView=
(TextView) findViewById(R.id.tv_header); mImageButton=
(ImageButton) findViewById(R.id.ib_header); //將從資源文件中加載的屬性設置給子控件 if
(!TextUtils.isEmpty(titleText)) setPageTitleText(titleText); setPageTitleTextColor(titleTextColor); setPageTitleTextSize(titleTextSize); } /** *
設置標題文字 *
@param text */ public
void
setPageTitleText(String text) { mTextView.setText(text); } /** *
設置標題文字顏色 *
@param color */ public
void
setPageTitleTextColor( int
color) { mTextView.setTextColor(color); } /** *
設置標題文字大小 *
@param size */ public
void
setPageTitleTextSize( float
size) { mTextView.setTextSize(size); } /** *
設置按鈕點擊事件監聽器 *
@param listener */ public
void
setOnHeaderClickListener(OnClickListener listener) { mImageButton.setOnClickListener(listener); } } |
自定義屬性文件:attrs.xml
1
2
3
4
5
6
7
8
9
|
<? xml
version = "1.0"
encoding = "utf-8" ?> < resources > <!--
自定義的屬性--> < declare-styleable
name = "Header" > < attr
name = "titleTextSize"
format = "dimension"
/> < attr
name = "titleTextColor"
format = "color"
/> < attr
name = "titleText"
format = "string" /> </ declare-styleable > </ resources > |
以下是引用方式,activity佈局文件:main.xml
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<? xml
version = "1.0"
encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "match_parent" android:layout_height = "match_parent" > <!--
注意需要加上命名空間 在eclipse開發工具中:使用 xmlns:app="http://schemas.android.com/apk/res/com.ivan.app1.widgets" 在IntelliJ
Idea或者Android Studio中以Gradle構建時,使用 xmlns:app="http://schemas.android.com/apk/res-auto" --> <!--
通過包的類的全名來引用自定義視圖--> < com.ivan.app1.widgets.Header android:id = "@+id/header" android:layout_width = "match_parent" android:layout_height = "48dp" android:background = "@color/black" app:titleText = "我是標題" app:titleTextColor = "#ff0000" app:titleTextSize = "12sp" /> < TextView
android:layout_width = "match_parent" android:layout_height = "match_parent" android:gravity = "center" android:text = "我是內容" android:textSize = "60sp" /> </ LinearLayout > |
主Activity類:MainActivity.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package
com.ivan.app1; import
com.ivan.app1.widgets.Header; import
android.os.Bundle; import
android.support.v7.app.AppCompatActivity; import
android.view.View; import
android.widget.Toast; /** *
User: xyh *
Date: 2015/6/2 *
Time: 10:30 */ public
class
MainActivity extends
AppCompatActivity { @Override public
void
onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); ((Header)findViewById(R.id.header)).setOnHeaderClickListener( new
View.OnClickListener() { @Override public
void
onClick(View v) { Toast.makeText(getApplicationContext(), "標題欄的按鈕被點擊了" ,Toast.LENGTH_LONG).show(); } }); } } |
運行結果:
原地址:http://www.cnblogs.com/ivan-xu/p/4545929.html?utm_source=tuicool