美文网首页Android
View的工作原理-v2

View的工作原理-v2

作者: 和莱 | 来源:发表于2021-02-08 16:41 被阅读0次

    ● MeasureSpec
    这是View类得一个静态内部类,可以理解为测量规格,和子View的测量有关,子View的测量还与LayoutParam类有关,这个类将父View的布局需要传递给子View,每一个MeasureSpec代表父View对子View在width或者height上的布局规格。
    MeasureSpec通过将SpecMode和SpecSize打包为一个int值,可以节省存储空间。SpecMode使用高两位表示,有三个取值,UNSPECIFIED,父View不限制子View,要多大给多大;EXACTLY,父View已经测出了子View所需大小,这个时候View的最终大小由SpecSize决定,对应LayoutParam的match_parent和具体数值两种模式,AT_MOST,父View指定一个可用大小SpecSize,子View不能超出这个大小,具体大小由要看不同view实现,对应LayoutParam的wrap_content。
    public static class MeasureSpec {
    private static final int MODE_SHIFT = 30;
    private static final int MODE_MASK = 0x3 << MODE_SHIFT;
    public static final int UNSPECIFIED = 0 << MODE_SHIFT;
    public static final int EXACTLY = 1 << MODE_SHIFT;
    public static final int AT_MOST = 2 << MODE_SHIFT;
    public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
    @MeasureSpecMode int mode) {
    if (sUseBrokenMakeMeasureSpec) {
    return size + mode;
    } else {
    return (size & ~MODE_MASK) | (mode & MODE_MASK);
    }
    }
    @UnsupportedAppUsage
    public static int makeSafeMeasureSpec(int size, int mode) {
    if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) {
    return 0;
    }
    return makeMeasureSpec(size, mode);
    }

        public static int getMode(int measureSpec) {
            return (measureSpec &amp; MODE_MASK);
        }
    
        public static int getSize(int measureSpec) {
            return (measureSpec &amp; ~MODE_MASK);
        }
    }
    

    在View测量的时候,系统会将LayoutParam结合父View的MeasureSpec计算出自己的MeasureSpec,比较特别的是顶级View,其Measure由自身的LayoutParam和窗口尺寸决定。MeasureSpec一旦确定,onMeasure就可以测量View的宽和高了;

    ● View的工作流程
    ● measure
    对于单个view,measure方法调用onMeasure,然后调用setMeasuredDimension存储调用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:计算的宽和高等于measureSpec中的SpecSize;
    case MeasureSpec.EXACTLY:
        result = specSize;
        break;
    }
    return result;
    

    }
    对于ViewGroup,出了调用自己的measure过程以外,还需要测量子View,measureChildern->对于每一个childView调用measureChild,计算出mwasureSpec,然后调用child的measure,这样将上一层的measure过程传递到了下一层;
    实际上在onCreate,onStart和onResume中均无法获得某个view的宽高信息,这是以为measure的测量过程和Activity的生命周期是不同步的,无法保证在某个生命周期时view已经测量完毕。可以重写onWindowFocusChanged来获得view的宽和高,这个方法会在Activity获得焦点和失去焦点时被调用;view.post(rRunnable action)将一个Runnable对象投递到消息队列尾,当执行到时,view已经测量完毕;ViewTreeObserver的很多回调借口也可以完成。

    ● layout过程用于确定view在父布局中的位置。layout->setFrame确定view四个顶点位置,接着调用onLayout方法,这个方法需要具体的ViewGroup实现,在这个方法中调用setChildFrame设置子View的四个顶点坐标,setChildFram中会调用子view的setFrame方法,这样就将layout过程传递到了下一层。
    ○ draw过程的作用是将view绘制到屏幕上,首先绘制背景background.draw(canvas),然后绘制自己,onDraw(),绘制children,diapatchDraw(),绘制装饰onDrawScrollBars。

    相关文章

      网友评论

        本文标题:View的工作原理-v2

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