Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android高频面试专题 - 提升篇(二)View绘制流程

Android高频面试专题 - 提升篇(二)View绘制流程

作者头像
Android扫地僧
发布于 2020-03-19 08:12:58
发布于 2020-03-19 08:12:58
9.8K00
代码可运行
举报
文章被收录于专栏:Android进阶Android进阶
运行总次数:0
代码可运行

View绘制流程,必问,请不要只会回答onMeasure,onLayout,onDraw,更多完整面试专题,请关注公众号获取。

1、View绘制的起点

提升篇(一)中提过,当建立好了decorView与ViewRoot的关联后,ViewRoot类的requestLayout()方法会被调用,以完成应用程序用户界面的初次布局。实际被调用的是ViewRootImpl类的requestLayout()方法,这个方法的主要源码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public void requestLayout() {
  if (!mHandlingLayoutInLayoutRequest) {
    // 检查发起布局请求的线程是否为主线程
    checkThread();
    mLayoutRequested = true;
    scheduleTraversals();
  }
}

上面的方法中调用了scheduleTraversals()方法来调度一次完成的绘制流程,该方法会向主线程发送一个“遍历”消息,最终会导致ViewRootImpl的performTraversals()方法被调用。下面,我们以performTraversals()为起点,来分析View的整个绘制流程。

2、View的绘制流程

View的绘制,有三个步骤:测量(measure),布局(layout),绘制(draw), 从DecorView自上而下遍历整个View树,注意是所有View执行完一个步骤后,再进行下一步,而不是一个View执行完所有步骤再遍历下一个View。

各步骤的主要工作:

  • Measure:测量视图大小。从顶层父View到子View递归调用measure方法,measure方法又回调OnMeasure。
  • Layout:确定View位置,进行页面布局。从顶层父View向子View的递归调用view.layout方法的过程,即父View根据上一步measure子View所得到的布局大小和布局参数,将子View放在合适的位置上。
  • Draw:绘制视图。ViewRoot创建一个Canvas对象,然后调用OnDraw()。六个步骤:①、绘制视图的背景;②、保存画布的图层(Layer);③、绘制View的内容;④、绘制View子视图,如果没有就不用;⑤、还原图层(Layer);⑥、绘制滚动条。

3、简单介绍下MeasureSpec

MeasureSpec由两部分组成,一部分是测量模式,另一部分是测量的尺寸大小。

其中,Mode模式共分为三类:

  • EXACTLY:对应LayoutParams中的match_parent和具体数值这两种模式。检测到View所需要的精确大小,这时候View的最终大小就是SpecSize所指定的值,
  • AT_MOST :对应LayoutParams中的wrap_content。View的大小不能大于父容器的大小。
  • UNSPECIFIED :不对View进行任何限制,要多大给多大,一般用于系统内部,如ListView,ScrollView

4、MeasureSpec的确定

这个没啥好说的,理解+记忆这个表格,子View的MeasureSpec由父View根据自身的MeasureSpec和子View的LayoutParams来共同确定子View的MeasureSpec,注意,即使确定了子View的MeasureSpec并不一定决定了子View的大小,自定义View可以根据需要修改这个值,最终通过setMeasuredDimension(width,height)设置最终大小。

5、View执行onMeasure,onLayout的次数

分析ViewRootImpl的源码,scheduleTraversales()内部会执行postCallBack触发mTraversalRunnable重新走一遍performTraversals(),第二次执行performTraversals()就会触发performDraw()。所以performTraversals()走了两次,那么肯定会走2次measure方法,但不一定走2次onMeasure(),读过View measure方法源码的都应知道measure方法做了2级测量优化:

  • 1.如果flag不为forceLayout或者与上次测量规格(MeasureSpec)相比未改变,那么将不会进行重新测量(执行onMeasure方法),直接使用上次的测量值;
  • 2.如果满足非强制测量的条件,即前后二次测量规格不一致,会先根据目前测量规格生成的key索引缓存数据,索引到就无需进行重新测量;如果targetSDK小于API 20则二级测量优化无效,依旧会重新测量,不会采用缓存测量值。

6、getWidth()和getMeasuredWidth()的区别

getMeasuredWidth()、getMeasuredHeight()必须在onMeasure之后使用才有效)getMeasuredWidth() 的取值最终来源于 setMeasuredDimension() 方法调用时传递的参数, getWidth()返回的是,mRight - mLeft,mRight、mLeft 变量分别表示 View 相对父容器的左右边缘位置,getWidth()与getHeight()方法必须在layout(int l, int t, int r, int b)执行之后才有效

7、如何在onCreate中拿到View的宽度和高度

  • View.post(runnable)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
view.post(new Runnable() {            
            @Override
            public void run() {
                int width = view.getWidth();
                int measuredWidth = view.getMeasuredWidth();
                Log.i(TAG, "width: " + width);
                Log.i(TAG, "measuredWidth: " + measuredWidth);
            }
        });

利用Handler通信机制,发送一个Runnable到MessageQueue中,当View布局处理完成时,自动发送消息,通知UI进程。借此机制,巧妙获取View的高宽属性,代码简洁,相比ViewTreeObserver监听处理,还不需要手动移除观察者监听事件。

  • ViewTreeObserver.addOnGlobalLayoutListener()

监听View的onLayout()绘制过程,一旦layout触发变化,立即回调onLayoutChange方法。 注意,使用完也要主要调用removeOnGlobalListener()方法移除监听事件。避免后续每一次发生全局View变化均触发该事件,影响性能。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ViewTreeObserver vto = view.getViewTreeObserver();       
       vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                Log.i(TAG, "width: " + view.getWidth());
                Log.i(TAG, "height: " + view.getHeight());
            }
        });

8、invalidate和postInvalidate区别

二者都会出发刷新View,并且当这个View的可见性为VISIBLE的时候,View的onDraw()方法将会被调用,invalidate()方法在 UI 线程中调用,重绘当前 UI。postInvalidate() 方法在非 UI 线程中调用,通过Handler通知 UI 线程重绘。

9、requestLayout()的作用

requestLayout()也可以达到重绘view的目的,但是与前两者不同,它会先调用onLayout()重新排版,再调用ondraw()方法。当view确定自身已经不再适合现有的区域时,该view本身调用这个方法要求parent view(父类的视图)重新调用他的onMeasure、onLayout来重新设置自己位置。特别是当view的layoutparameter发生改变,并且它的值还没能应用到view上时,这时候适合调用这个方法requestLayout()。

10、onDraw() 和dispatchDraw()的区别

  • 绘制View本身的内容,通过调用View.onDraw(canvas)函数实现
  • 绘制自己的孩子通过dispatchDraw(canvas)实现

draw过程会调用onDraw(Canvas canvas)方法,然后就是dispatchDraw(Canvas canvas)方法, dispatchDraw()主要是分发给子组件进行绘制,我们通常定制组件的时候重写的是onDraw()方法。值得注意的是ViewGroup容器组件的绘制,当它没有背景时直接调用的是dispatchDraw()方法, 而绕过了draw()方法,当它有背景的时候就调用draw()方法,而draw()方法里包含了dispatchDraw()方法的调用。因此要在ViewGroup上绘制东西的时候往往重写的是dispatchDraw()方法而不是onDraw()方法,或者自定制一个Drawable,重写它的draw(Canvas c)和 getIntrinsicWidth()方法,然后设为背景。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Android扫地僧 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
重新复习Android View的绘制流程
PhoneWindow是Android系统中最基本的窗口系统,每个Activity会创建一个。同时,PhoneWindow也是Activity和View系统交互的接口。DecorView本质上是一个FrameLayout,是Activity中所有View的祖先。
老马的编程之旅
2022/06/22
4530
重新复习Android View的绘制流程
Android经典面试题之View的三大流程
View的三大流程指的是measure(测量)、layout(布局)、draw(绘制)。
AntDream
2024/07/10
1290
Android经典面试题之View的三大流程
Android组件View绘制流程原理分析
如上图,Activity的window组成,Activity内部有个Window成员,它的实例为PhoneWindow,PhoneWindow有个内部类是DecorView,这个DecorView就是存放布局文件的,里面有TitleActionBar和我们setContentView传入进去的layout布局文件
Anymarvel
2018/10/22
1.3K0
Android组件View绘制流程原理分析
View绘制流程
1. View 树的绘图流程 当 Activity 接收到焦点的时候,它会被请求绘制布局,该请求由 Android framework 处理.绘制是从根节点开始,对布局树进行 measure 和 dr
xiangzhihong
2018/02/05
8620
View绘制流程
View的工作原理
View的绘制流程是从ViewRoot的PerformTraversals方法开始的。它经过measure,layout,draw三个过程将view绘制出来。mesure用来测量view的宽高,layout用来确定位置,draw绘制。流程图如下
提莫队长
2019/02/21
5570
Android中View是如何绘制的
View的绘制过程从ViewRootImpl.performTraversals()方法开始。
对话、
2022/02/22
2.3K0
带你彻底搞懂-View的工作原理!
1.ViewRoot对应ViewRootImpl类,是连接WindowManager和DecorView的纽带。View的三大流程是通过ViewRoot完成的。 在ActivityThread中,当Activity对象被创建完毕时,会将DecorView添加到Window中,同时会创建ViewRootImpl,且ViewRootImpl和DecorView会建立关联。如下代码,WindowManagerGlobal的addView()方法:
胡飞洋
2020/07/23
1.2K0
带你彻底搞懂-View的工作原理!
Android视图绘制流程完全解析,带你一步步深入了解View(二)
在上一篇文章中,我带着大家一起剖析了一下LayoutInflater的工作原理,可以算是对View进行深入了解的第一步吧。那么本篇文章中,我们将继续对View进行深入探究,看一看它的绘制流程到底是什么
用户1158055
2018/01/05
1.5K0
Android视图绘制流程完全解析,带你一步步深入了解View(二)
手把手教你读懂源码,View的绘制流程详细剖析
上一篇文章我们分析了View的加载流程,今天我们继续来深入学习View的绘制流程,接着上次的View绘制开始,同样使用的是Android 7.1源码。 1、回顾addView方法 上篇文章从a
分享达人秀
2018/02/02
1.5K0
手把手教你读懂源码,View的绘制流程详细剖析
深入解析Android中View的工作原理
Android中的任何一个布局、任何一个控件其实都是直接或间接继承自View实现的,当然也包括我们在平时开发中所写的各种炫酷的自定义控件了,所以学习View的工作原理对于我们来说显得格外重要,本篇博客,我们将一起深入学习Android中View的工作原理。
老马的编程之旅
2022/06/22
1K0
深入解析Android中View的工作原理
View的工作原理
在 WindowManagerGlobal 的 addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) 方法中,创建了 ViewRootImpl 对象,将 ViewRootImpl 和 DecorView 相关联:
俞其荣
2022/07/28
1.2K0
View的工作原理
View的工作原理
ViewRoot对应于ViewRootImpl类,它是连接WindowManager和DecorView的纽带,View的三大流程均是通过ViewRoot完成的。在ActivityThread中,当Activity对象被创建完毕后,会将DecorView添加到Window中,同时创建ViewRootImpl对象,并将ViewRootImpl对象和DecorView建立关联,这个过程可参看源码:
见得乐
2022/07/20
4460
View的工作原理
这可能是2020大小厂问的最经典的Android面试题了——事件分发机制、View渲染过程
Activity和View只有两个方法控制事件传递:dispatchTouchEvent(),onTouchEvent ();
Android技术干货分享
2021/01/07
1.1K0
这可能是2020大小厂问的最经典的Android面试题了——事件分发机制、View渲染过程
Android高级进阶之路【一】Android中View绘制流程浅析
一个View,从无到有会走三个流程,也就是老生常谈的measure,layout,draw三流程;
做个快乐的码农
2021/11/17
1.3K0
Android高级进阶之路【一】Android中View绘制流程浅析
android之View绘制
Android系统的视图结构的设计也采用了组合模式,即View作为所有图形的基类,Viewgroup对View继承扩展为视图容器类,由此就得到了视图部分的基本结构--树形结构 View定义了绘图的基本
xiangzhihong
2018/01/30
7650
android之View绘制
View的绘制流程源码分析
概述 View的绘制流程主要是指测量、布局以及绘制显示,在View中,measure是测量View的宽高,layout是控制View四个顶点的位置,而draw就是将布局直接绘制出来。 Measure流程 measure的流程氛围View的measure流程以及ViewGroup的measure的流程。之所以把View和ViewGroup分开就是因为ViewGroup不仅仅要测量自身的宽高,而且还需要通过递归将子view的宽高测量出来。 View的measure过程 View的measure说简单也简单,说复
我就是马云飞
2018/02/05
6440
Android View底层到底是怎么绘制的
Android绘制链图: 网上很多讲Android  view的绘制流程往往只讲到了Measure - Layout - Draw。 但是,这只是一个大体的流程,而我们需要探讨的是Android在
xiangzhihong
2018/02/05
1.1K0
Android View底层到底是怎么绘制的
android视图学习---从源码角度来理解onMeasure过程
view的绘制:onMeasure onLayout onDraw 执行流程  【这里其实就是RootViewImpl 里面setView之后的一个流程】
wust小吴
2019/07/08
6250
高级 UI 成长之路 (三) 理解 View 工作原理并带你入自定义 View 门
该篇分为上下结构,上部分主要讲解 View 的工作原理,下部分主要以案例的形式讲解自定义 View。
做个快乐的码农
2021/11/16
8670
高级 UI 成长之路 (三) 理解 View 工作原理并带你入自定义 View 门
【Android 应用开发】UI绘制流程 ( 生命周期机制 | 布局加载机制 | UI 绘制流程 | 布局测量 | 布局摆放 | 组件绘制 | 瀑布流布局案例 )
ApplicationThread 内部类 : 该类与上面的代码没有直接调用关系, ActivityThread 与 ApplicationThread 关联后, 系统就可以通过调用 一系列的 schedule 方法控制 Activity的各种状态了;
韩曙亮
2023/03/27
1.2K0
【Android 应用开发】UI绘制流程  ( 生命周期机制 | 布局加载机制 | UI 绘制流程 | 布局测量 | 布局摆放 | 组件绘制 | 瀑布流布局案例 )
推荐阅读
相关推荐
重新复习Android View的绘制流程
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档