笔记:View的工作原理

View的工作原理


  • ViewRoot 和DecorView

ViewRoot对应于ViewRootImpl类,它是连接DecorView和WindowManager的纽带,View的三大绘制流程都是通过ViewRoot来完成。

在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImpl,并将ViewRootImpl对象和DecorView对象关联。


Activity中View的绘制流程是从ViewRoot的perfromTraversals()方法开始的,它经过measure layout draw 最终将View绘制出来


笔记:View的工作原理_第1张图片

  • MeasureSpec 代表32位int值,高2位代表specMode,低30位代表specSize

specMode:测量模式

specSize:在某种测量模式下的规格大小

  • SpecMode 类型

UNSPECIFIED: 父容器不对View限制,要多大有多大,这种情况一般用于系统内部,表示一种测量状态。

EXACTLY: 父容器已经检测出View所需要的精确大小,这个时候View的最终大小就是SpecSize所指定的值,它对应于LayoutParams中的Match_parent和具体的值。

AT_MOST: 父容器指定了一个可视大小,即SpecSize,View的大小不能大于这个值,具体要看不同View的具体实现,对应于wrap_content


  • ******父容器和LayoutParams一起决定View的MeasureSpec

系统会将LayoutParams在父容器的约束下转换成对应的MeasureSpec,然后再根据MeasurSpec来确定View测量后的宽高。


  • 父容器测量子View P181


  • DecorView对MeasureSpec的转换测量有点差别,其MeasureSpec值由窗口尺寸和其自身的LayoutParams来决定

笔记:View的工作原理_第2张图片

  • View 的mesure方法会调用onMeasure方法,所有只需要实现View的onMeasure就可以了。

View的measure方法又会被所在的ViewGroup的measureChild方法调用。measureChild方法会遍历child,执行child的measure。

  • 在onMeasure中又调用了setMeasureDimension()方法设置View宽高的测量值。

  • 在measure完以后,通过getMeasuredWidth/Height()可获得测量后的宽/高

  • View的Measure过程和Activity的生命周期过程不同步,

  • 如何在Activity中获取View的宽/高?

  1. Activity/View #onWindowFouceChanged()方法,表示View已经初始化完毕,宽高已经准备好

    但该方法会在Acitivty焦点获取或失去时都会调用,也就是onResume和onPause都会调用。

  2. view.post(runnable)

    view初始化完毕会执行runnable,在run()中view.getMesuredWidth()/height

  3. ViewTreeObserver

    当View树状态发生改变,或者View树内部的View发生改变,onGlobalLayout方法会被调用,在这里获取View的宽高。

    @Override
    protected void onStart() {
        super.onStart();
        ViewTreeObserver viewTreeObserver = vMarqueeView.getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                vMarqueeView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = vMarqueeView.getMeasuredWidth();
                int height = vMarqueeView.getMeasuredHeight();
            }
        });
    }
  1. view.measure(int widthMesureSpec,int heightMesureSpec) p192

MATCH_PARENT:不可用,因为不知道父容器的尺寸

WRAP_CONTENT:

        int widthMesureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
        int heightMesureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
        vMarqueeView.measure(widthMesureSpec, heightMesureSpec);

(1<<30)-1 代表(2^30-1) 即使用最大值去构造MeasureSpec(View的尺寸使用30位二进制表示)


  • layout过程和mearsure过程一样,调用父元素的layout方法,layout方法调用onLayout方法,onlayout方法又会遍历子元素,调用子元素的layout,子元素layout又会调用onLayout,如此循环

  • View的测量宽高和最终宽高的区别:

getWidth()和getMesuredWidth()

本质上是相等的,只是,getWidht()值mWitdh形成于onLayout之后,而getMesuredWidth()的值形成于mesured之后

(p196)

注意:如过在onLayout中改变了l,r,t,b中某个值,则会影响到getWidth/getHeight,而不会影响getMesuredWidth/Height值


  • draw过程有点差别,但大致相同

调用draw方法,draw方法会执行如下几步

1.绘制背景(background.draw(cavans))

2.绘制自己(onDraw)

3.绘制children(dispatchDraw(),dispatchDraw又会循环child执行其draw()方法)

4.绘制装饰(onDrawScrollBars)


  • View的setWillNotDraw(boolean willNotDraw) 优化

如果View不做任何绘制内容时,那么设置这个标志位位true后,系统会进行相应的优化,默认情况下,View没有启用这个标志位,但ViewGroup会启用

当自定义View继承ViewGroup且本身不具备绘制功能时,可以开启这个标志位,从而便于系统的后续优化,当明确知道继承ViewGroup的View需要通过onDraw绘制相应内容时,需要显示的关闭这个标志位


  • 绘制自定义View须知: p201
  1. 让View支持wrap_content

直接继承View或ViewGroup的控件,如果不在onMeasure中对wrap_content做特殊处理,那么在外界布局中使用wrap_content就无法达到预期效果。

  1. 如果有必要,让View支持padding

直接继承View的控件,如果不在draw方法中处理padding,那么padding属性无法起作用。另外,直接继承ViewGroup的控件要在其onMeasure和onLayout中要考虑padding和子元素margin对其造成的影响,不然将导致padding和子元素的margin失效

  1. 尽量不要在View中使用Handler

View内部本身提供了post方法

  1. 如果View中有线程或者动画,需及时停止,参考View#onDetachedFromWindow

当Activity退出或者当前View被remove后,View的onDetachedFromWindow将会被调用,对应的方法是onAttachedToWindow(),该方法在onDraw之前任何时候调用,不确定在onMesure之前还是之后调用,当包含该View的Activity被启动时调用。

  1. View带有滑动嵌套时,需要处理好滑动嵌套

  • 再次强调,自定义组件继承View或ViewGroup的,padding值需要自己处理,在onDraw中处理padding,而margin值由父类处理,对于wrap_content,默认是按照match_parent处理,所以也需要自己处理wrap_content情况,设置个最小值。
笔记:View的工作原理_第3张图片

  • 自定义属性 p206

你可能感兴趣的:(笔记:View的工作原理)