ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AndroidUI绘制流程

2022-07-07 13:40:15  阅读:160  来源: 互联网

标签:ViewGroup ViewRootImpl AndroidUI 方法 流程 视图 DecorView 绘制 View


基础知识-底层View对象

ViewParent

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

DecorView

ContentView的父容器

ViewRootImpl

在 ActivityThread 中,当 Activity 对象被创建完毕后,会将 DecorView 添加到 Window 中,同时会创建 ViewRootImpl 对象,并将 ViewRootImpl 对象和 DecorView 建立关联,将 DecorView 实例对象交给 ViewRootImpl 用以绘制 View 。最后调用 ViewRootImpl 类中的 performTraversals(),从而实现视图的绘制。

正文

根据APP启动流程,从ActivityThread.handleLaunchActivity()开始,调用了performLaunchActivity() 和 handleResumeActivity()两个方法。下面分别讲一下。

performLaunchActivity

performLaunchActivity()方法中,创建了Activity对象,执行了生命周期,创建了PhoneWindow对象,初始化DecorView,添加布局到DecorView的Content。

PhoneWindow对象创建:performLaunchActivity()->activity.attach()->mWindow = new PhoneWindow()

初始化DecorView:PhoneWindow.setContentView()->installDecor()->创建decorView对象,为decorView的contentView设置布局

添加布局到DecorView的Content : PhoneWindow.setContentView()->mLayoutInflater.inflate(layoutResID, mContentParent); ?

handleResumeActivity

handleResumeActivity()方法中,调用了Activity.onResume,wm.addview()。

我们看看 WindowManagerGlobal 的 addView() 方法。

handleResumeActivity()->WindowManagerGlobal.addview()->ViewRootImpl.setView()->ViewRootImpl->requestLayout()->ViewRootImpl.scheduleTraversals()->ViewRootImpl.mChoreographer.postCallback( Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null)->ViewRootImpl.performTraversals()

——》performMeasure()计算View树种各个空间显示,需要多大的尺寸

    performLayout()从根View开始,递归完成UI的布局工作

    performDraw()从根View开始,完成所有所有View和ViewGroup的绘制工作,根据布局过程计算出的显示区域,将内容画到屏幕上。

我们都知道一个视图要经历三个主要流程,onDraw,onMeasure,onLayout。他们明显对应上述的几个方法

performMeasure

performMeasure()->mView.measure()//根据强制布局标志位和needsLayout标识位决定是否测量->View.onMeasure()->View.setMeasuredDimension()//完成宽高成员变量的赋值

一个布局中一般都会包含多个子视图,每个视图都需要经历一次 measure 过程。ViewGroup 中定义了一个 measureChildren() 、measureChild()、measureChildWithMargins() 方法来去测量子视图的大小,三个方法最终都是调用子视图的 measure() 方法 对于非 ViewGroup 的 View 而言,通过调用上面默认的 onMeasure() 即可完成 View 的测量(当然你也可以重载 onMeasure() 并调用 setMeasuredDimension() 来设置任意大小的布局,这里就可以根据实际需求来决定,也就是说,如果你不想使用系统默认的测量方式,可以按照自己的意愿进行定制)。

performLayout

performLayout()->host.layout()//host即DecorView->ViewGroup.layout()->super.layout()->View.Layout()

->View.onLayout()

  setOpticalFrame()

  setFrame()

根据之前measure测量的尺寸和其他属性,确定View的位置

layout() 方法会调用 setFrame() 方法,setFrame() 方法是真正执行布局任务的步骤,至于 setOpticalFrame() 方法,其中也是调用 setFrame() 方法,通过设置 View 的 mLeft、mTop、mRight 和 mBottom 四个参数来执行布局,对应描述了 View 相对其父 View 的位置。

在 setFrame() 方法中会判断 View 的位置是否发生了改变,以确定有没有必要对当前的视图进行重绘。

而对子 View 的局部是通过 onLayout() 方法实现的,由于非 ViewGroup 视图不含子 View,所以 View 类的 onLayout() 方法为空,正因为 layout 过程是父布局容器布局子 View 的过程,onLayout() 方法对叶子 View 没有意义,只有 ViewGroup 才有用

再看一下ViewGroup.onlayout()方法

onLayout()->layoutChildren()->child.layout()

可以看得到,这里面也是对每一个子视图调用 layout() 方法的。如果该子视图仍然是父布局,会继续递归下去;如果是叶子 view,则会走到 view 的 onLayout() 空方法,该叶子view布局流程走完。

在 onLayout() 过程结束后,我们就可以调用 getWidth() 方法和 getHeight() 方法来获取视图的宽高值.

这一阶段主要是根据上一阶段得到的测量值来确定View的最终位置

performDraw

performDraw()->draw()->drawSoftware()->DecorView.draw()

有7个步骤,我们重点分析其中两个

onDraw

这个方法里面什么都没做,但是注释讲得很清楚,重写该方法以完成你想要的绘制。因为每个 View 的内容部分是各不相同的,所以需要由子类去实现具体逻辑。以 DecorView 为例,这里 ViewGroup 和 FrameLayout 都没有重写 onDraw() 方法,只有 DecorView 重写了该方法。DecorView 重写 onDraw() 在里面实现自己需要的绘制。

dispatchDraw

注释说明了如果 View 包含子类需要重写该方法,实际上对于叶子 View 来说,该方法没有什么意义,因为它没有子 View 需要画了,而对于 ViewGroup 来说,就需要重写该方法来画它的子 View。

RelativeLayout、LinearLayout、DecorView 之类的布局并没有重写 dispatchDraw() 方法,那我们就直接来看 ViewGroup 里面:

遍历子 View ,调用 drawChild(),以绘制每个子视图:

drawChild() 方法里面直接就只有调用子 View 的 draw() 方法,非常明了。同样的,如果该子 View 还有子视图,也会继续遍历下去调用 drawChild() 方法,继续绘制子 View,直到叶子 View 为止,这样不断递归下去,直到画完整棵 DecorView 树。

标签:ViewGroup,ViewRootImpl,AndroidUI,方法,流程,视图,DecorView,绘制,View
来源: https://www.cnblogs.com/MiraculousB/p/16418242.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有