Android进阶知识(十四):View的工作流程之Layout过程和Draw过程

Android进阶知识(十四):View的工作流程之Layout过程和Draw过程

一、Layout过程

  Layout过程的作用是ViewGroup用来确定子元素的位置,当ViewGroup的位置被确定后,它在onLayout方法中会遍历所有子元素并调用其layout方法,在layout方法中onLayout方法又会被调用。
  Layout过程比Measure过程简单,layout方法确定View本身的位置,而onLayout方法则会确定所有子元素的位置
在这里插入图片描述

  layout方法的大致流程如下:首先会通过setFrame方法设定View的四个顶点的位置,即初始化mLeft、mRight、mTop和mBottom,View的四个顶点一旦确定,View在父容器中的位置也就确定;接着调用onLayout方法,用于父容器确定子元素位置。
  Layout过程大致流程如下图所示。
在这里插入图片描述

  从上面可以看到,在layout方法中,setFrame设置View的四个顶点位置,即初始化mLeft、mRight、mTop和mBottom,这也是View的最终大小。在前两篇内容中,笔者一直强调measure过程是确定View的测量宽/高,原因在于View的最终大小是在layout过程确定的,所以必须加已区分,但几乎所有情况下View的测量大小和最终大小相等

二、Draw过程

  Draw过程比较简单,其作用是将View绘制到屏幕上。View的绘制过程遵循如下几步:

  • 绘制背景drawBackground (canvas)
  • 绘制自己(onDraw)
  • 绘制children(dispatchDraw)
  • 绘制装饰(onDrawScrollBars)

  以下是draw方法的核心源码,通过源码可以更容易理解上述步骤。

public void draw(Canvas canvas) {
    final int privateFlags = mPrivateFlags;
    mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
    /*
    * Draw traversal performs several drawing steps which must be executed
    * in the appropriate order:
    *
    *      1. Draw the background
    *      2. If necessary, save the canvas' layers to prepare for fading
    *      3. Draw view's content
    *      4. Draw children
    *      5. If necessary, draw the fading edges and restore layers
    *      6. Draw decorations (scrollbars for instance)
    */
    // Step 1, draw the background, if needed
    int saveCount;
    drawBackground(canvas);
    
    // skip step 2 & 5 if possible (common case)
    final int viewFlags = mViewFlags;
    boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
    boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
    if (!verticalEdges && !horizontalEdges) {
        // Step 3, draw the content
        onDraw(canvas);
        // Step 4, draw the children
        dispatchDraw(canvas);
        drawAutofilledHighlight(canvas);
        // Overlay is part of the content and draws beneath Foreground
        if (mOverlay != null && !mOverlay.isEmpty()) {
            mOverlay.getOverlayView().dispatchDraw(canvas);
        }
        // Step 6, draw decorations (foreground, scrollbars)
        onDrawForeground(canvas);
        // Step 7, draw the default focus highlight
        drawDefaultFocusHighlight(canvas);
        if (debugDraw()) {
            debugDrawFocus(canvas);
        }
        // we're done...
        return;
    }
    
    // ......
}

  Draw过程流程可以大致表示为下图所示。
在这里插入图片描述

在前两篇内容中也提到了,View的Draw过程和Measure过程和Layout过程不同,onDraw用于绘制自身,而Draw过程的传递是通过dispatchDraw来实现的,dispatchDraw方法会遍历调用所有子元素的draw,如此draw事件就一层层地传递下去。

参考资料:《Android开发艺术探索》

原创文章 78 获赞 25 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_38196407/article/details/105864264