View的测量、布局和绘制过程中的关键方法

简介: 我们这里说的View的测量、布局和绘制,实质上是针对ViewGroup的,简单起见就不区分View和ViewGroup。View的测量、布局和绘制是包含在ViewGroup流程中的。

View的测量、布局和绘制过程中的关键方法

我们这里说的View的测量、布局和绘制,实质上是针对ViewGroup的,简单起见就不区分View和ViewGroup。View的测量、布局和绘制是包含在ViewGroup流程中的。

流程概览

View的测量、布局、绘制是从ViewRootImpl开始的,它是Activity中的根View。具体是在ViewRootImpl#performTraversals方法中依次调用performMeasure、performLayout、performDraw。

我们常见的更新UI的方法View#invalidate最终就是通过调用ViewRootImpl#performTraversals方法来完成的,具体参见View#invalidate方法是如何更新UI的

如下图所示:

ViewRootImpl#performTraversals图解

本文的源码基于android-28的api。

Measure流程

Measure的具体流程如下:

ViewRootImpl#performTreversals() -->
ViewRootImpl#performMeasure() -->
View#measure() --> 
View#onMeasure
如果是ViewGroup,一般会重写View#onMeasure方法,会在ViewGroup#onMeasure方法中循环调用子View的measure方法,如此循环往复,直到最终调用了所有的View#onMeasure方法。

Layout流程

Layout的具体流程如下:

ViewRootImpl#performTreversals() -->
ViewRootImpl#performLayout() -->
View#layout() --> 
View#onLayout()

View#onLayout方法默认空实现,如下所示,

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

所以onLayout方法需要View根据需求各自实现。

与onMeasure方法类似,ViewGroup一般会重写View#onLayout方法。
然后在ViewGroup#onLayout方法中循环调用子View的layout方法,如此循环往复,直到最终调用了所有的View#onLayout方法。

这里以LinearLayout为例,

LinearLayout#onLayout -->
Linearlayout#layoutVertical -->
循环遍历每个子View,调用Linearlayout#setChildFrame -->
最终调用View#layout方法。

Draw流程

Draw的具体流程如下:

ViewRootImpl#performTreversals() -->
ViewRootImpl#performDraw() -->
ViewRootImpl#draw(boolean fullRedrawNeeded) --> 
View#drawSoftware -->
View#draw(Canvas canvas) -->
绘制当前View:View#onDraw(Canvas canvas) --> 
绘制子View:View#dispatchDraw(Canvas canvas)

View#draw(Canvas canvas)方法中,有如下注释:

/*
 * 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)
 */

绘制流程按照以下六个步骤执行:
①绘制背景
②如果需要,保存图层
③绘制当前View的内容
④绘制子View
⑤如果需要,绘制边界,恢复图层
⑥绘制相关装饰(比如滚动条)

对应的源码为:为了方便阅读,省略了无关代码。

public void draw(Canvas canvas) {
    ...

    /*
     * 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
    if (!dirtyOpaque) {
        drawBackground(canvas);
    }
    ...

    // Step 2, save the canvas' layers
    ...
    saveCount = canvas.getSaveCount();

    // Step 3, draw the content
    if (!dirtyOpaque) onDraw(canvas);

    // Step 4, draw the children
    dispatchDraw(canvas);

    // Step 5, draw the fade effect and restore layers
    ...

    canvas.restoreToCount(saveCount);
    drawAutofilledHighlight(canvas);

    // Step 6, draw decorations (foreground, scrollbars)
    onDrawForeground(canvas);

}
相关文章
|
7月前
|
XML 前端开发 数据可视化
View的绘制流程
View的绘制流程
45 1
|
7月前
|
调度 Android开发
自定义View之理解测量onMeasure和布局onLayout过程
自定义View之理解测量onMeasure和布局onLayout过程
72 0
|
存储 前端开发
canvas自定义绘制顺序解决遮挡问题
canvas自定义绘制顺序解决遮挡问题
258 0
|
前端开发 JavaScript
【Three.js入门】渲染第一个场景及物体(轨道控制器、坐标轴辅助器、移动缩放旋转)
【Three.js入门】渲染第一个场景及物体(轨道控制器、坐标轴辅助器、移动缩放旋转)
304 0
|
JSON 前端开发 数据可视化
【图形基础篇】02 # 指令式绘图系统:如何用Canvas绘制层次关系图?
【图形基础篇】02 # 指令式绘图系统:如何用Canvas绘制层次关系图?
202 0
【图形基础篇】02 # 指令式绘图系统:如何用Canvas绘制层次关系图?
|
前端开发 容器
View的测量、布局和绘制过程中父View(当前View)和子View的先后顺序
View的测量、布局和绘制过程中,到底是先测量(布局、绘制)父View,还是先测量子View,这篇文章会从源码角度给出答案。
|
前端开发 Android开发 开发者
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
383 0
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(一)
|
vr&ar Android开发
【Android 应用开发】Paint 图形组合 Xfermod 之 合成模式表示方法 ( Xfermod 使用步骤 | 透明度 颜色值 公式表示方法 | 老版本表示方法 | 合成区域分块 )
【Android 应用开发】Paint 图形组合 Xfermod 之 合成模式表示方法 ( Xfermod 使用步骤 | 透明度 颜色值 公式表示方法 | 老版本表示方法 | 合成区域分块 )
226 0
【Android 应用开发】Paint 图形组合 Xfermod 之 合成模式表示方法 ( Xfermod 使用步骤 | 透明度 颜色值 公式表示方法 | 老版本表示方法 | 合成区域分块 )
减小TabLayout高度而不影响每个tab展示的几种方法
在Support Design库中有一个新的组件TabLayout,配合TabItem实现tab页面的形式。 但是图标和文字组合的tab的默认情况下,TabLayout中的tab太高,占据太多布局。 但是如果直接将TabLayout高度改小,很容易出现图标显示不全的情况,因为图标和字体及两者的间距没有跟着改变。 这时可以从几个方面处理:
322 0
|
Android开发 异构计算
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(二)
【Android 性能优化】布局渲染优化 ( 过渡绘制 | 自定义控件过渡绘制 | 布局文件层次深 | GPU 过渡绘制调试工具 | 背景过度绘制 )(二)
200 0