MeasureSpec、自定义View、自定义ViewGroup

2017-03-16  本文已影响0人  jiting45

32位的,前2位表示测量模式,后30位表示测量值。
MeasureSpec是有自己的Layoutparmes和父容器的尺寸决定的。

自定义View继承View的实现形式下:
xml中设置wrap_content和设置成match_parent具有相同的效果。
原因:View是没有处理WRAP_CONTENT的情况的。
View的onMeasure方法:

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;
        }
        return result;
    }

AT_MOST和EXACTLY下都会设置成测量值。AT_MOST对应的就是wrap_content,EXACTLY对应的就是match_parent,因此设置成wrap_content和match_parent会有相同的效果。
但是为什么会是match_parent的效果呢?
因为View的绘制是从ViewRootImpl开始的,ViewRootImpl的performTraversals分别进行measure、layout、draw过程,绘制会先从顶级View开始,顶级View是一个ViewGroup,它会遍历所有的子View,view的onMeasure中的参数就是ViewGroup传进去的,因此测量值就是match_parent 的效果。

解决方案:
重写view的onMeasure时,在AT_MOST的模式下,设置成一个默认值和测量值两者的小的值。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int desiredWidth = 100;
    int desiredHeight = 100;

    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int width;
    int height;

    //Measure Width
    if (widthMode == MeasureSpec.EXACTLY) {
        //Must be this size
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        width = Math.min(desiredWidth, widthSize);
    } else {
        //Be whatever you want
        width = desiredWidth;
    }

    //Measure Height
    if (heightMode == MeasureSpec.EXACTLY) {
        //Must be this size
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        //Can't be bigger than...
        height = Math.min(desiredHeight, heightSize);
    } else {
        //Be whatever you want
        height = desiredHeight;
    }

    //MUST CALL THIS
    setMeasuredDimension(width, height);
}

自定义ViewGroup的时候会不会调用onDraw方法?
如果自定义的ViewGroup的背景backgroud为空,就不会调用onDraw。相反如果backgroud不为空就会调用onDraw方法。
为了让自定义的ViewGroup会调用onDraw方法,可以通过如下方式:
1、设置ViewGroup的backgroud
2、调用setWillNotDraw(false),去掉其WILL_NOT_DRAW这个Flag

上一篇下一篇

猜你喜欢

热点阅读