美文网首页
从源码看onMeasure、onLayout、onDraw

从源码看onMeasure、onLayout、onDraw

作者: 冬冬269 | 来源:发表于2018-09-05 19:36 被阅读0次

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来创建。

image.png

源码分析结束后,可以得到上面一个表。源码不贴了。太占地方,这个表是某大神画的。创建好了之后就调用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被关闭。

相关文章

网友评论

      本文标题:从源码看onMeasure、onLayout、onDraw

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