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.apkbus.com/data/attachment/forum/201506/02/145717dpjjnnntp9akmnpm.jpg)
原地址:http://www.cnblogs.com/ivan-xu/p/4545929.html?utm_source=tuicool