实际上的自定义控件很多种类型,但现在基本上非原生控件都叫做自定义控件,那么今天就来研究研究自定义控件到底是个啥。
自定义控件分类
这里的分类是依照实现方式进行的。自定义控件可以分为以下几种类型:
一、继承原生控件的View
- 简单重写其中方法
- 改变控件布局
二、继承原生布局的ViewGroup
- 修改其中的方法
- 修改控件布局
- 设置指定子View
自定义控件实现
自定义控件种类繁多,实现方式也是各种各样,也正是因为多样化的设计才让Android的控件永远不乏新意。(只有你想不到,没有我做的到( ̄ε(# ̄)☆╰╮( ̄▽ ̄///))
关于自定义控件最重要的就是三个方法,也就是传说中的onMeashure()、onLayout()、onDraw()
别的不扯,自定义控件所需要的基本设置有哪些,具体研究一下,这一点很重要:
1.继承View它的子类(包括ViewGroup)
说要自定义控件,总归来说做的还是一个控件,所以还是要做继承,只是做个自定义View,总不至于连View都自己写。
完成继承以后,根据所要做的自定义View不同,那么要进行的工作也就不一样了,一般来说,尽量继承与自定义控件结构相似的已有控件,这也是为了减少工作量。举个例子,想要做一个很酷炫的文本输入框,那直接继承EditText就好,要什么效果再做具体修改。没必要从继承View开始,那样会毁灭世界的。(没那么夸张,当时真的没那个必要)
2.做自定义内容设置
这一步就要分为两种种情况了,分开两种讲:
- 第一种:继承View
继承View的做法,表示当前没有存在哪些能够满足或是靠近你要求的控件存在,此时我们就要自己创造一个,一般的步骤如下:
1.复写构造方法
//这个是用来初始化控件的
/**打个比方**/
public class CustomerView extends View{
public CustomerView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomerView (Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomerView (Context context) {
super(context);
}
}
2.重写onMeasure()方法
这个方法是用来控制控件的宽高值的
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//参数widthMeasureSpec和heightMeasureSpec分别指代行准确测量值以及高准确测量值,根据父类的onMeasure(),它们是存在自己的默认值的,根据父控件以及本身的宽高属性(wrap_content之类)来确定值。
//而在这个方法中,也可以由程序设定时自行制定
//注意这个方法,这是最终设置控件的宽高值
setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
}
3.重写onDraw()方法
我知道onLayout()方法不见了,但是我真的没吃它,事实上,View是不存在onLayout()方法的,原因是onLayout()用来控制控件中的布局,但是View中是不存在子View的(单身控(#‵′)凸),因此直接完成onDraw()方法基本就能搞定这个自定义控件了。
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//看到了Canvas以后,一切都明了了,这个控件现在是个画板了,想在上面画什么,全凭大家的需求和想象力了。
}
4.完善工作
自定义控件毕竟不是只用来看的,不然请UI切份图给我们就好了,还写一大块的代码干嘛,需要声明控件中的各种各样七七八八的功能都能在里面完成,提供给应用使用,还能在里面添加观察者,说到观察者,有兴趣可以移步http://blog.csdn.net/baidu_20596139/article/details/50930716,也是我写的,可以交流一下
- 第二种:继承已有控件
同样是自定义的View,这一种自定义控件相对来说就简单了很多。首先,这个控件的基本结构已经存在了,那么做这一种继承一般是为了修改控件中的一些方法或是某些显示方式,那么要做的就是:1.继承 2. 复写
需要对哪修改就复写哪个方法,简单快捷,赞一个(^o^)/YES!
但是!! 不得不说,当需要高个性化的控件,这种方法真的就没什么用处了,还是需要使用第一种方式。
说完了继承View的情况,还有一种继承ViewGroup的情况
1.继承ViewGroup
选择一个与需求最为匹配的布局作为父类,能够帮助快速方便的完成自定义控件的设计。
2.根据需求选择完成方式:
- 有指定的布局样式
- 修改原布局部分功能
- 指定内部布局方式或绘制内容
首先是有指定布局样式:
//通过这句代码将指定的布局添加到ViewGroup中,这里的viewGroup就应该是this
View.inflate(context,layout,viewGroup);
完成了这个步骤,接下来有其他的需要就可以编写其他的方法进行控件的操作。
另一个是修改原布局功能:
这其实是一个小部分的方法重写,实现也很简单,一般我用来处理事件传递方法。
再一个就是有自行绘制需求
这一点中onMeasure()和onDraw()参考View的继承就行,基本上是一样的,这里讲一下onLayout()。
这个方法是用来设置子View的摆放的,也就是说ViewGroup中放置View的位置可以由这个方法完成。
protected abstract void onLayout(boolean changed,int l,int t,int r,int b){
//在该方法中能够设定各个子View的位置
//可以使用获取子View
getChild()
}
基本简单的自定义控件完成方法都介绍完了,事实上还有很多详细的实现方法以及其他的实现方式,在这片文章里就不做介绍了。