美文网首页Android面试
(十一)View绘制机制面试问题

(十一)View绘制机制面试问题

作者: lkmc2 | 来源:发表于2017-07-31 13:32 被阅读75次

    一、View树的绘制流程

    measure-->layout-->draw

    measure:是否重新计算视图大小。

    layout:是否需要重新安置视图位置。

    draw:是否需要重绘。

    二、measure

    measure 和 layout流程

    1.ViewGroup.LayoutParams :用来指定视图高度和宽度的参数,不包括Padding。

    2.MeasureSpec :表示测量规格。32位的Int值,高二位表示模式,后三十位表示测量规格的大小。

    (1)UNSPECIFIED:不限定子视图尺寸大小。

    (2)EXACTLY:父容器会为子视图确定一个尺寸大小,无论子视图要求多大,都要在父容器的限制内。

    (2)AT_MOST:父容器会为子视图指定一个最大的尺寸,子视图所有的大小都必须在这个尺寸范围内。对应wrap_content。此时父容器无法获取子视图的大小,只能子视图自己根据需求设定。

    ViewGroup.LayoutParams最终会被封装成MeasureSpec。

    measure——重要方法

    measure会从父容器遍历子View的measure方法,会根据ViewGroup.MeasureSpec和子View的LayoutParams来决定子视图的测量规格,通过这个测量规格进一步获取到子View的宽高,一层一层向下传递,不断保存整个父容器的测量宽高。

    1.measure:该方法会调用onMeasure方法。

    2.onMeasure:该方法会调用setMeasuredDimension()方法。

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

    3.setMeasuredDimension():该方法完成整个的测量过程。

    protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
            boolean optical = isLayoutModeOptical(this);
            if (optical != isLayoutModeOptical(mParent)) {
                Insets insets = getOpticalInsets();
                int opticalWidth  = insets.left + insets.right;
                int opticalHeight = insets.top  + insets.bottom;
    
                measuredWidth  += optical ? opticalWidth  : -opticalWidth;
                measuredHeight += optical ? opticalHeight : -opticalHeight;
            }
            setMeasuredDimensionRaw(measuredWidth, measuredHeight);
    }
    

    三、layout

    onLayout方法是用来设置与父容器的摆放关系的,自定义View需重写该方法。

    View中的onLayout是个空方法。

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    }
    

    LinearLaout中的onLayout如下:

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        if (mOrientation == VERTICAL) {
            layoutVertical(l, t, r, b);
        } else {
            layoutHorizontal(l, t, r, b);
        }
    }
    

    四、draw

    两个容易混淆的方法:

    1.invalidate():请求系统重绘,未发生变化时不会调用。

    2.requestLayout():当布局(方向、尺寸等)发生变化时,需手动调用,该方法会触发measure和layout的过程,而不会调用draw方法。

    相关文章

      网友评论

        本文标题:(十一)View绘制机制面试问题

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