1.View
measure(int widthMeasureSpec, int heightMeasureSpec)
做下判断forcelayout,needslayout,调用onMeasure方法。
onMeasure(widthMeasureSpec,HeightMeasureSepc)
MeasureSpec
干嘛的
int值,里面封装了size和mode。节省内存。在view的OnMeasur中主要就是解析widthMeasureSpec和hightMeasureSpec中的mode和size。根据其中的mode和size,得到view的测量后大小。
哪来的。
是由这个view的父空间viewgroup的MeasureSpec和view本身的LayoutParams来决定的,父空间调用getChildMeasureSpec来创建。
源码分析结束后,可以得到上面一个表。源码不贴了。太占地方,这个表是某大神画的。创建好了之后就调用view.measure,view.measure在调用onmeasure,这个measurespec就给到view了。
怎么用
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
看一下getDefaultSize(int,int)
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;
}
return result;
}
如果measureSpec的mode是UNSPECIFIED。宽/高=size。这个size是多少呢。我们看getSuggestedMinimumWidth()
protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}
如果mode是EXACTLY。宽/高 = measureSpec自带的,根据表可知道,就是自身的设置的宽高。
如果mode是AT_MOST。宽/高 = measureSpec自带的,根据表可知,就是父类剩余的宽高。
是否设置背景图,没有就mMinWidth 系统默认,一般是0,由就背景图宽高。
那么我们知道了之后,如果我们设置了wrapcontent,不想使用父类的剩余宽高,我们可以在onMeasure做判断,通过setMeasureDimension然后自己设置宽高。代码如下
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if(widthMode == MeasureSpec.AT_MOST &&heightMode == MeasureSpec.AT_MOST){
setMeasuredDimension(200,200);
}else if(widthMode == MeasureSpec.AT_MOST){
setMeasuredDimension(100,height);
}else if(heightMode == MeasureSpec.AT_MOST){
setMeasuredDimension(width,100);
}
viewgroup的measure
image.png没有自己onMeasure方法和measure方法,提供了measureChildren方法直接遍历子view,去创建他们的measureSpec,然后调用view的measure把measureSpec传过去进行测量。
viewgroup是一个抽象类,onMeasure需要子类去实现。因为不同的viewgroup子类有不同的特性,无法统一实现。大概看了一下linearLayout的onMeasure方法,有vertical和horizontal。matchparent或者固定宽高的onmeasure和view一样,不同的是子view测量完毕后,会绘制linearlayout。根据所以子空间的高度加起来来绘制linearlayout,不多说了。
layout
layout用来确定自身位置,自身位置确定后,调用onlayout确定子view的位置。view和viewgroup没有实现onlayout。具体实现是由子类实现的。
layout中调用setframe,onlayout中调用setChildframe。
getMeasureWidth和getWidth的区别。一个形成于measure,一个在layout。正常情况是相等的。在layout中super.layout(l,t,r+100,b+100)。那么就不相等,但没什么意义。
draw
dispatchdraw,调用子的draw方法。
drawBackgrodun(canvas);
ondraw(canvas);
dispatchdraw(canvas)
ondrawScroolBars(canvas)
setWillNotDraw,当一个view不需要绘制任何内容时,这个标记为true,系统会进行相应优化。viewgroup默认开启。我们的自定义viewgroup如果不需要绘制可以设为true,明确知道需要ondraw来绘制内容,我们需要显示关闭WILL_NOT_DRAW标记位。
onDetachenFromWindow 处理view被关闭。
网友评论