一、简介
在自定义View时,我们通常会重写onDraw()方法来绘制View的显示内容。如果,该View还需要使用wrap_content属性,那么还必须重写onMeasure()方法。另外,通过自定义attrs属性,还可以设置新的属性配置值。
在View中通常有以下一些比较重要的回调方法:
- onFinisInflate():从XML加载组件后回调;
- onSizeChanged():组件大小改变时回调;
- onMeasure():回调该方法来进行测量;
- onLayout():回调该方法来确定显示位置;
- onTouchEvent():监听到触摸事件时回调;
当然,创建自定义View的时候,并不需要重写所有方法,只需要重写特定条件的回调方法即可。
通常情况下,有以下三种方法来实现自定义的控件:
- 对现有控件进行拓展;
- 通过组合来实现新的控件;
- 重写View来实现全新的控件;
二、实例:
一、创建复合控件
1. 定义属性
为一个View提供可自定义的属性非常简单,只需要在res资源目录的values目录下创建一个attrs.xml的属性定义文件,并在该文件中通过如下代码定义相应的属性即可。
1 <?xml version="1.0" encoding="utf-8"?>
2 <resources>
3 <declare-styleable name="TopBar">
4 <attr name="title" format="string" />
5 <attr name="titleTextSize" format="dimension" />
6 <attr name="titleTextColor" format="color" />
7 <attr name="leftTextColor" format="color" />
8 <attr name="leftBackground" format="reference|color" />
9 <attr name="leftText" format="string" />
10 <attr name="rightTextColor" format="color" />
11 <attr name="rightBackGround" format="reference|color" />
12 <attr name="rightText" format="string" />
13 </declare-styleable>
14 </resources>
我们在代码中通过<declare-styleable>标签声明了使用自定义属性,并通过name属性来确定引用的名称。最后,通过<attr>标签来声明具体的自定义属性,比如:标题文字、颜色、大小等属性。并通过format属性来指定属性的类型。需要注意的是,有些属性可以是颜色属性,也可以是引用属性。比如:按钮的背景,可以把其指定为具体颜色,也可以把它指定为一张图片,所以,使用“|”来分隔不同的属性——"reference|color"。
在构造方法中,通过如下代码来获取在XML布局文件中自定义的那些属性,即与我们使用系统提供的那些属性一样。
1 /**
2 * attrs : 属性设置
3 * R.styleable.TopBar : 在attrs.xml文件中,配置的属性
4 */
5 TypeArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
示例代码如下所示:
1 public class TopBar extends View
2 {
3 protected Color mLeftTextColor;
4
5 public TopBar(Context context)
6 {
7 this(context, null);
8 }
9
10 public TopBar(Context context, AttributeSet attrs)
11 {
12 super(context, attrs);
13 // 通过这个方法将在attrs.xml文件中,定义的<declare-styleable>的所有属性的值存储到TypedArray中
14 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
15
16 // 在TypedArray中,取出对应的值来为要设置的属性赋值
17 mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
18
19 // 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误
20 ta.recycle();
21 }
22 }
PS: 需要注意的是,当获取完所有的属性值后,需要调用TypedArray的recyle()方法来完成资源的回收。
2. 组合控件
1 public class TopBar extends RelativeLayout
2 {
3 protected String mTitle;
4 protected float mTitleTextSize;
5 protected int mTitleTextColor;
6 protected int mLeftTextColor;
7 protected Drawable mLeftBackground;
8 protected String mLeftText;
9 protected int mRightTextColor;
10 protected Drawable mRightBackground;
11 protected String mRightText;
12
13 public Button mLeftButton;
14 public TextView mTitleView;
15 public Button mRightButton;
16
17 protected RelativeLayout.LayoutParams mLeftLayoutParams;
18 protected RelativeLayout.LayoutParams mTitleLayoutParams;
19 protected RelativeLayout.LayoutParams mRightLayoutParams;
20
21 public TopBar(Context context)
22 {
23 this(context, null);
24 }
25
26 public TopBar(Context context, AttributeSet attrs)
27 {
28 super(context, attrs);
29 // 通过这个方法将在attrs.xml文件中,定义的<declare-styleable>的所有属性的值存储到TypedArray中
30 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TopBar);
31
32 // 在TypedArray中,取出对应的值来为要设置的属性赋值
33 // left button
34 mLeftTextColor = ta.getColor(R.styleable.TopBar_leftTextColor, 0);
35 mLeftBackground = ta.getDrawable(R.styleable.TopBar_leftBackground);
36 mLeftText = ta.getString(R.styleable.TopBar_leftText);
37
38 // title
39 mTitleTextSize = ta.getDimension(R.styleable.TopBar_titleTextSize, 10);
40 mTitleTextColor = ta.getColor(R.styleable.TopBar_titleColor, 0);
41 mTitle = ta.getString(R.styleable.TopBar_titleText);
42
43 // right button
44 mRightTextColor = ta.getColor(R.styleable.TopBar_rightTextColor, 0);
45 mRightBackground = ta.getDrawable(R.styleable.TopBar_rightBackGround);
46 mRightText = ta.getString(R.styleable.TopBar_rightText);
47
48 // 获取完TypedArray的值后,一般要调用recyle方法来避免重新创建的时候的错误
49 ta.recycle();
50
51 initView(context);
52 }
53
54 private void initView(Context context)
55 {
56 mLeftButton = new Button(context);
57 mTitleView = new TextView(context);
58 mRightButton = new Button(context);
59
60 mLeftButton.setText(mLeftText);
61 mLeftButton.setBackground(mLeftBackground);
62 mLeftButton.setTextColor(mLeftTextColor);
63
64 mTitleView.setText(mTitle);
65 mTitleView.setTextColor(mTitleTextColor);
66 mTitleView.setTextSize(mTitleTextSize);
67
68 mRightButton.setText(mRightText);
69 mRightButton.setBackground(mRightBackground);
70 mRightButton.setTextColor(mRightTextColor);
71
72 mLeftLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
73 mLeftLayoutParams.addRule(ALIGN_PARENT_LEFT, TRUE);
74 addView(mLeftButton, mLeftLayoutParams);
75
76 mTitleLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
77 mTitleLayoutParams.addRule(CENTER_IN_PARENT, TRUE);
78 addView(mTitleView, mTitleLayoutParams);
79
80 mRightLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
81 mRightLayoutParams.addRule(ALIGN_PARENT_RIGHT, TRUE);
82 addView(mRightButton, mRightLayoutParams);
83 }
84
85 }
3. 定义接口
定义接口对象,在TopBar控件中,实现左右按钮的点击事件,调用接口方法:
1 // 定义接口
2 mLeftButton.setOnClickListener(new OnClickListener()
3 {
4 @Override
5 public void onClick(View v)
6 {
7 mListener.leftClick();
8 }
9 });
10
11 mRightButton.setOnClickListener(new OnClickListener()
12 {
13 @Override
14 public void onClick(View v)
15 {
16 mListener.rightClick();
17 }
18 });
19
20 ......
21
22 // 左右按钮接口类
23 public interface TopBarClickListener
24 {
25 void leftClick();
26 void rightClick();
27 }
28
29 // 设置左右按钮点击事件接口实现的实例
30 public void setOnTopBarClickListener(TopBarClickListener topBarClickListener)
31 {
32 mListener = topBarClickListener;
33 }
4. 引用UI模板
在引用UI模板前,需要指定引用第三方控件的命名空间。在布局文件中,如下所示:
1 xmlns:androi="http://schemas.android.com/apk/res/android"
这行代码就是在指定引用的名字控件xmlns,即xml namespace。这里指定了命名空间为“android”,因此,在接下来使用系统属性的时候,才可以使用“android:”来引用Android的系统属性。同样地,使用自定义的属性,那么就需要创建自己的命名空间,在Android Studio中,第三方控件 都使用如下代码引入命名空间:
1 xmlns:custom="http://schemas.android.com/apk/res-auto"
这里引用的第三方命名空间为custom,之后在XML文件中使用自定义的属性时,就可以通过这个命名空间来引用,代码如下所示:
1 <?xml version="1.0" encoding="utf-8"?>
2 <com.naray.radialview.View.TopBar
3 xmlns:android="http://schemas.android.com/apk/res/android"
4 xmlns:custom="http://schemas.android.com/apk/res-auto"
5 android:layout_width="wrap_content"
6 android:layout_height="wrap_content"
7 custom:titleText="自定义控件"
8 custom:titleColor="#da0c0c"
9 custom:titleTextSize="18sp"
10 custom:leftBackground="#999999"
11 custom:leftTextColor="#da0c0c"
12 custom:leftText="back"
13 custom:rightBackGround="#999999"
14 custom:rightTextColor="#da0c0c"
15 custom:rightText="more">
16
17 </com.naray.radialview.View.TopBar>
使用自定义的View与系统原生的View最大的区别就是在申明控件时,需要指定完整的包名,而在引用自定义的属性时,需要使用自定义的xmlns名字。