您的位置:首页 > 移动开发 > Android开发

View 的绘制流程

2016-06-08 15:01 477 查看
View的measure 过程由其measure方法完成,measure 方法是一个final类型的方法,子类不能重写。在view的mesure方法中会调用onmeasure 我们只看onMeasure方法就可了。

View源码:

protected void onMeasure(

int widthMeasureSpec,
int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(
getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}


看着很简单。setMeasuredDimension 方法会设置view的宽高测量值,我们只看getDefaultSize 方法即可

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: //wrap_content
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}

可以看出getDefaultSize 方法很简单,我们只看MOST,EXACTLY就可以简单的说getDefaultSize方法返回值就是measureSpec View测量后宽高。 为什么要说测量后,view的最终宽高在onlayout阶段确定的。所以不许加以区分。但是几乎所有情况下view的 onMeasure,onLayout中的值是一样。

至于UNSPECIFIED,一半用于系统内部测量,宽高就为第一个参数的值 getSuggestedMinimumWidth(), getSuggestedMinimumHeight(), 简单分析一个另个方法类似这里就不进行分析

protected int getSuggestedMinimumWidth() {
return (mBackground == null) ? mMinWidthmMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
}


逻辑同样是很清晰,mBackground ==null 时候 返回mMinWidth,而mMinWidth 就是android:minWidth属性值,当然如果不进行设置默认minWidth=0。那么mBackground指的是Drawable.getMinimumWidth()

public int getMinimumWidth() {
final int intrinsicWidth = getIntrinsicWidth();
return intrinsicWidth > 0 ? intrinsicWidth : 0;
}


返回的是Drawable的原始宽度,前提是这个Drawable有原始宽度。那么问题来了Drawable什么情况下没有原始宽度?

ShapeDrawable没有原始宽度,而BitmapDrable有原始宽度

在总结一下getSuggestedMinimumWidth逻辑。view没有设置背景怎么返回minWidth (如果minWidth没有设置值默认为0),view设置了背景则返回mBackground 和 minWIdth中最大的值。

那通过上面可以推出来自定义view需要重写onMesure 方法。并且 宽高值设置wrap_content 和 match_parent 是一样的效果

为什么会出现上面情况

switch (specMode) {
case MeasureSpec.UNSPECIFIED: //系统内部使用
result = size;
break;
case MeasureSpec.AT_MOST: //wrap_content
case MeasureSpec.EXACTLY:
result = specSize;
break;
}


设置 wrap_content的模式为AT_MOST:这样view的宽高为specSize等于parentSize ,很显然view的宽高就等于父容器剩余空间的大小。这种和在不居中使用match_parent完全一致如何解决这样问题。也很简单。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
//如果宽高与 MeasureSpec.AT_MOST 相等。则宽高等于默认宽高
//宽与MeasureSpec.AT_MOST 相等。则宽等于默认宽
//高与MeasureSpec.AT_MOST 相等。则高等于默认高
}


具体宽高默认值给多少根据具体需求。

Eg:可以查看其他系统组件是如何处理 默认宽高值。这里就不进行分析
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  view android