美文网首页
View绘制流程

View绘制流程

作者: dw_0920 | 来源:发表于2019-07-11 15:51 被阅读0次

View绘制流程

此文章为自己的一个笔记。

一.onCreate()

从Activity的生命周期来说,从onCreate()方法开始,那么,页面的布局应该从onCreate()方法里的setContentVIewI()说起。

  • setContentVIew()源码如下:

    public void setContentView(int layoutResID) {
            getWindow().setContentView(layoutResID);
            initWindowDecorActionBar();
        }
    
    • 调用当前Window的setContentView方法。
    • initWindowDecorActionBar()
  • Window的setContentView()源码如下:

    @Override
        public void setContentView(int layoutResID) {
            if (mContentParent == null) {
                installDecor();
            } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                mContentParent.removeAllViews();
            }
    
            if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
                final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                        getContext());
                transitionTo(newScene);
            } else {
                mLayoutInflater.inflate(layoutResID, mContentParent);
            }
            final Callback cb = getCallback();
            if (cb != null && !isDestroyed()) {
                cb.onContentChanged();
            }
        }
    
    • installDecor()创建了DecorView。
      • 同时解析了对该Activity做的一些显示配置:如:是否浮动、是否支持状态栏、全屏、颜色、过场动画等。
      • DecorView默认inflate了一个布局,包含actionBar和contentView。
      • 由此我们可以得出:


        image
    • LayoutInflater.inflate()用来加载xml布局。
      • 方法内会先遍历拿到根节点
      • 若根节点不是<merge>,创建一个rootView,若是则不再创建,直接使用现有的root布局(父布局)。
      • 将该布局的子View加载到rootView/root下。

二.onResume()

View真正的绘制,是从onResume()开始。

  • 从ActivityThread的handleResumeActivity()方法开始,会调用到WindowManageImpl的addView()方法,最后调用ViewRootImpl的performTraversals()方法,进入View的绘制。

  • performTraversals()方法内,会拿到DecorView,然后依次执行测量(Measure)、布局(Layout)、绘制(draw)

    • 在执行Measure()方法前,会先通过测量模式和测量大小,得出子View的WidthMeasureSpecHeightMeasureSpec,然后作为参数传入测量方法,该方法不可重写,只能重写该方法下的onMeasure()方法。三个测量模式如下:

      • UNSPECIFIED

        未指定模式,View想多大就多大,通常在绘制自定义View时才会用,不常用。

      • AT_MOST

        最大值模式,当空间的宽高设置为wrap_content时。

      • EXACTLY

        精确值模式,当控件的layout_width和layout_height属性指定为具体数值或match_parent时。

      • 这里需要注意一点,自定义控件时,AT_MOST和EXACTLY返回的尺寸均为父容器的大小,所以需要自己实现。

    • 对于View来说,在layout()方法下会确定自己的位置(mLeft,mRight,mTop,mBottom四个值),而对于ViewGroup来说,在确定自己的位置之后,还需调用onLayout()方法来给子View确定位置。

      • 自定义ViewGroup时,必须实现onLayout()方法,而View则不必。
      • 在ViewGroup内实现onLayout()方法时,由于已经确定自己的位置,所以可以直接调用getHeight()getWidth()
      • 这里有一个回调方法叫OnLayoutChangeListener(),用来监听View的位置变化,通过addOnLayoutChangeListener()方法添加。
    • View的绘制是通过draw()方法实现的,一般遵循以下几个步骤:

      • 绘制背景 -- drawBackground()
      • 绘制自己 -- onDraw()
      • 绘制孩子 -- dispatchDraw()
      • 绘制装饰 -- onDrawScrollbars()

相关文章

网友评论

      本文标题:View绘制流程

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