美文网首页
MeasureSpec、自定义View、自定义ViewGroup

MeasureSpec、自定义View、自定义ViewGroup

作者: jiting45 | 来源:发表于2017-03-16 18:33 被阅读0次

    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

    相关文章

      网友评论

          本文标题:MeasureSpec、自定义View、自定义ViewGroup

          本文链接:https://www.haomeiwen.com/subject/dchjnttx.html