Android知识点-View
View绘制
主要方法
- Measure:测量计算控件大小
- Layout:确定绘制位置
- Draw:开始绘制
MeasureSpec
MeasureSpec由一个32位的整形组成,其中高2位是mode,后30位是size。可以通过MeasureSpec.getMode() 和 MeasureSpec.getSize() 方法获得相应的值。
MeasureSpec有三种模式:
- UNSPECIFIED:父容器对子容器没有限制,子容器要多大就多大
- EXACTLY:父容器已经检测出View所需要的精确大小,这个时候View的大小就是SpecSIze所指定的值。他对应于LayoutParams中的match_parent和具体的数值这两种模式。
- AT_MOST:父容器指定了一个可用大小SpecSize。View的大小不能超过这个值,它对应于LayoutParams的wrap_content。
View中measure()方法是final的,其中调用了onMeasure()方法,需要自定义测量可以覆写此方法。
Layout
Draw
invalidata():如有有变化才绘制 requestlayout():请求重新测量和确定位置,不绘制。
事件分发机制
Andorid中View是树形结构,触摸事件产生后需要重上到下分发事件,确定需要处理。
事件类型
事件指的是用户触摸产生的拦截机制,主要是在MotionEvent类中的几个常量,分别是:
- ACTION_DOWN:按下
- ACTION_UP:抬起
- ACTION_MOVE:移动
- ACTION_CANCEL:取消
事件分发流程以及主要涉及的方法
产生了一个MotionEvent之后,系统会将该事件传递给Activity -> ViewGroup -> View处理。
- dispatchTouchEvent():表示是否消费了当前事件
- onInterceptTpuchEvent():只存在ViewGroup中,判断是否需要拦截
- onTouchEvent():真正对MotionEvent进行处理,在dispatchTouchEvent进行调用。
//三个方法之间的关系
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean consume = false;//事件是否被消费
if (onInterceptTouchEvent(ev)){//调用onInterceptTouchEvent判断是否拦截事件
consume = onTouchEvent(ev);//如果拦截则调用自身的onTouchEvent方法
}else{
consume = child.dispatchTouchEvent(ev);//不拦截调用子View的dispatchTouchEvent方法
}
return consume;
}
其中如果onInterceptTpuchEvent方法返回True,直接会调用onTouchEvent方法,不会向下传递事件。
如果都不拦截事件的话,完整流程是这样:
- Acivity.dispatchTouchEvent() ->
- ViewGroupA.onInterceptTpuchEvent() ->
- ViewGroupB.onInterceptTpuchEvent() ->
- View.onTouchEvent() ->
- ViewGroupB.onTouchEvent() ->
- ViewGroupA.onTouchEvent() ->
- Acivity.onTouchEvent()
为了更好的理解,盗了网上的一张图
返回值
- True:表示拦截此事件,不需要继续传递
- False:不拦截,继续传递事件。
注意点
- 如果设置了onTouchListener,那么OnTouchListener方法中的onTouch方法会被回调。onTouch方法返回true,则onTouchEvent方法不会被调用(onClick事件是在onTouchEvent中调用)所以三者优先级是onTouch->onTouchEvent->onClick