为什么要自定义控件?
1,对自己的app特定的,独一无二的控件展示,来契合自己app的主风格
2,处理特特有的用户交互,比如点击一段英文文本,然后依据用户点击的单词给出响应,可以弹出此单词的发音和释义
3,优化布局,比如我的app中要做很多个switchButton,进行一个封装,优化布局,减少嵌套
自定义控件的流程和步骤是什么?
1,自定义属性的声明与获取
2,测量onMeasure
3,布局onLayout(ViewGroup)
4,绘制onDraw
5,onTouchEvent
6,onInterceptTouchEvent
大致分为以上6步,接下里简单说一下这6个步骤
<1>自定义属性的声明与获取:
1,分析需要自定义的属性都有什么,以及是什么样的自定义名称和自定义的属性的值.有color,string,dimension,reference,enum等等
2,分析好之后在res/value/新建attrs.xml中定义和声明
3,在layout xml文件中进行使用,定义view的宽高以及自定义属性的值
4,在View的构造方法中进行获取,通过typedArray a=context. obtainStyledAttributes进行获取.
<2>测量onMeasure
1,自定义View需要测量自身的大小以及自身到底是个什么样子,View测量,其父容器测量子View通过次方法,测量View由两个数字来决定,一个是测量的模式,一个是测量的值.测量的模式分为三种:
(1),EXACTLY,是我们设置了一个明确的值,比如说,宽100dp,高50dp.
/**
* widthMeasureSpec, heightMeasureSpec这两个参数是从哪里来的?
* onMeasure()函数由包含这个View的具体的ViewGroup调用,因此值也是从这个ViewGroup中传入的。
* 子类View的这两个参数,由ViewGroup中的layout_width,layout_height和padding以及View自身的layout_margin共同决定。
* 权值weight也是尤其需要考虑的因素,有它的存在情况可能会稍微复杂点。
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//此处我们测量View的宽度,先声明为0;
int result = 0;
//获得View的模式为三种模式的哪一种
int mode = MeasureSpec.getMode(widthMeasureSpec);
//获得View的size
int size = MeasureSpec.getSize(widthMeasureSpec);
//如果View的模式为EXACTLY,就是我们设置了一个明确的值,比如说,宽100dp,那直接赋值即可
if (mode == MeasureSpec.EXACTLY){
result = size;
}else{
//如果自定义的View的尺寸不是明确的值的话,也就是模式为AT_MOST或者UNSPECIFIED
//那么View的宽高就需要自己获得自己的宽度
result = "需要的高度"+getPaddingLeft()+getPaddingRight();
if (mode == MeasureSpec.AT_MOST){
//如果模式为AT_MOST的话,View的最大不能超过父控件传下来的size的值
result = Math.min(result,size);
}
}
}
(2) AT_MOST, 是View最多不能超过某个值. 一般出现在我们设置View的大小为wrap _ content时,意味View的大小是由自身的内容去匹配的,并且最大的尺寸不能超过父容器的宽度或者高度..
(3),UNSPECIFIED, 是View 没有限制,多大多宽多高都可以,主要用于scrollView和listView中去,
2,MeasureSpec 是一个辅助类, View的测量是由模式和值来决定的,模式和值一般会封装MeasureSpec中,由View的父控件传递下来..通过此类去获得View的mode和size.
3,测量完毕之后, 需要调用setMeasureDimension来把最终测量的结果传递进去
4,requestLayout(); 当一个textView中的文本发生变化的时候,此View需要重新测量,调用requestLayout方法来重新测量..此方法不包括重新绘制..
<3>布局onLayout(viewGroup)
继承自ViewGroup的时候需要重写此方法,来决定子View的位置,
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() == GONE){
continue;
}
//计算left,top,right,bottom的值
child.layout(l,t,r,b);
//出发onlayout 也调用requestLayout
}
}
<4>onDraw , 绘制自身显示的样子.
1,绘制的是内容区域的.
2,如果测量值,属性发生变化,重新绘制, invalidate()–主线程.postinvalidate()–子线程
3,Canvas.drawXXX
4,translate rotate scale skew 等画布的状态
5,save restore 保存状态
<5>onTouchEvent
1,ACTION_DOWN
ACTION_UP
ACTION_MOVE
2,ACTION_POINTER_DOWN
ACTION_POINTER_UP
多点触控
唉,还有很多很多…知识的海洋??哈哈,我笑了,应该是知识的宇宙,要学习的东西永远都是那么那么多…兴趣才是关键…加油..
本篇博客整理自鸿洋大神慕课网视频..