Activity ——PhoneWindow——DectorView——rootViewGroup——子View
一个完整的事件流程是从Down开始的,UP结束,我们称作这为一个事件序列。某一事件序列经过触摸屏传递各个View,由各个view来处理这一事件的过程,即为事件分发。事件分发的三个重要方法:
-
dispatchTouchEvent(MotionEvent ev) :用来进行事件的分发
-
onInterceptTouchEvent(MotionEvent ev) :用来进行事件的拦截,dispatchTouchEvent中调用该方法,view中未提供该方法。
-
onTouchEvent(MotionEvent ev) :用来处理Touch事件,dispatchTouchEvent中调用。
点击事件传递的规则,用伪代码表示如下:
public boolean dispatchTouchEvent(MotionEvent ev){
boolean res = false;
if(onInterceptTouchEvent(ev)) { // 拦截后自己处理
res = onTouchEvent(ev);
}else {
res = child.dispatchTouchEvent(ev); // 分发
}
return res;
}
自定义属性
-
attrs.xml文件declare-styleable标签定义及相关属性
-
在布局文件中导入自定义的属性集。两种方法
xmlns:custom=“http://schemas.android.com/apk/res/com.example”
xmlns:custom=“http://schemas.android.com/apk/res-auto”
- 代码中如何获取自定义属性值
TypedArray arry = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
float size = arry.getDimension(R.styleable.CustomView_size,10f);
// to use
ViewGroup绘制流程
View和ViewGroup绘制流程基本相同,只是ViewGroup除了绘制自己还需要绘制子控件。绘制流程分为测量 ——布局——绘制 主要对应下面三个函数:
-
onMeasure():测量当前控件大小并为布局提供建议
-
onLayout():使用layout()函数对所有子控件进行布局
-
onDraw():根据测量布局的位置绘图
measure流程和MeasureSpec
MeasureSpec是int型数字,但它由两部分组成mode+size,它转换为二进制前两位代表模式后30位代表数值,它有三种模式。MeasureSpec是View的内部类,作用是在Measure的过程中,将View的LayoutParams根据父容器所分发的规则转换成对应的MeasureSpec,最后在onMeasure根据该值确定View的宽高。
-
UNSPECIFIED: 未指定模式,子View不受父View的限制,子View可以设置任意大小。一般用于系统内部的测量。
-
EXACTLY:精确模式,对应于match_parent和具体数值,子元素被限定于给定的边界。
-
AT_MOST:最大模式,对应于wrap_content,父控件给子控件分配的SpecSize。
作为顶层的View,它没有父容器。DecorView的getRootMeasureSpec方法第一个参数windowSize是指窗口尺寸,它的MeasureSpec由自身的LayoutParams和窗口尺寸大小决定。
特别需要注意的是,wrap_content对应AT_MOST,当布局文件中配置为EXACTLY模式时,我们就直接使用该值即可,当模式为AT_MOST,我们还需要将大小设置为我们计算的值,该值应该是包含控件最大值。
View的measure流程 : 先判断有无背景,取mMinWidth和背景的最小宽度的最大值; 再通过measureSpec获取默认大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
public static int getDefaultSize(int size, int measureSpec) {
int result = size;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
switch (specMode) {
case MeasureSpec.UNSPECIFIED:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
总结
其实客户端开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
然而Android架构学习进阶是一条漫长而艰苦的道路,不能靠一时激情,更不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!