1,自定义View的绘制流程?
- 第一步:复写onMeasure方法。
先measureChild方法 测量出所有子控件的moMeasure,
//1,测量自身
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//2,为每个子view计算测量的限制信息
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//3,把上一步确定的限制信息,传递给每一个子view,然后子view开始measure自己的尺寸
int childCount = getChildCount();//子view的个数
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
ViewGroup.LayoutParams lp = child.getLayoutParams();
int childWidthSpec = getChildMeasureSpec(widthMeasureSpec, 0, lp.width);
int childHeightSpec = getChildMeasureSpec(heightMeasureSpec, 0, lp.height);
child.measure(childWidthSpec, childHeightSpec);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
//测量子view 获取到当前子view的测量的宽度和高度
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
调用 setMeasuredDimension(int measuredWidth, int measuredHeight)设置测绘后的大小。
Log.i("tag","width = " + width );
Log.i("tag","height = " + height );
// 6,保存自身的尺寸
setMeasuredDimension(width, height);
- 第二步:onLayout方法
在方法调用getChildCount方法 获取到子条目数量。
用for循环遍历出每一个子条目的对象。 通过对象.layout方法 给子控件设置摆放位置。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
//1,遍历子view的
int left = 0;
int top = 0;
int right = 0;
int bottom = 0;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
left = i * OFFSET;
right = left + child.getMeasuredWidth();
bottom = top + child.getMeasuredHeight();
child.layout(left, top, right, bottom);//不考虑padding,margin等
top += child.getMeasuredHeight();
}
}
- 第三步:首先调用ViewGroup的disPatchDraw方法绘制ViewGroup。然后调用View中的onDraw方 进行绘制。
2,自定义View是如何测量的 MeasureSpec
方法内部需要调用MeasureSpec类 可以获取到view的模式 和 大小;
MeasureSpec.getMode()获取模式
MeasureSpec.getSize()获取大小
模式:
- MeasureSpec.EXACTLY 精确值模式: 表示父控件已经确切的指定了子视图的大小。
- MeasureSpec.AT_MOST 最大值模式:表示子查看具体大小没有尺寸限制,但是存在上限,上限一般为父视图大小。
- MeasureSpec.UNSPECIFIED 父控件没有给子视图任何限制,子视图可以设置为任意大小
什么时候这个模式会用到呢,看这边文章https://www.cnblogs.com/liushilin/p/11055741.html
onDraw方法:
用于绘制自定义View。
主要使用到了Canvas 画布对象。 和Paint 画笔对象 进行的绘制。
3,invalidate和postInvalidate方法的区别?requestLayout
- requestLayout方法会导致View的onMeasure、onLayout、onDraw方法被调用;
- invalidate方法则只会导致View的onDraw方法被调用;
- invalidate方法和postInvalidate方法都是用于进行View的刷新,invalidate方法应用在UI线程中,而postInvalidate方法应用在非UI线程中,用于将线程切换到UI线程,postInvalidate方法最后调用的也是invalidate方法。
- 我们在自定义View时,当需要刷新View时,如果是在UI线程中,那就直接调用invalidate方法,如果是在非UI线程中,那就通过postInvalidate方法来刷新View
- postInvalidate方法实现了消息机制,最终调用的也是invalidate方法来刷新View
- invalidate方法最终调用的是ViewRootImpl中的performTraversals来重新绘制View
4 View的Touch事件分发流程?
Touch事件的一般传递流程Activity->window(唯一实现类PhoneWindow)->顶级View(DecorView)->VIewGroup->View
详情:预留
网友评论