Android View的绘制流程

我写文章基本都会先把定义理解清楚,再去写代码和分析问题。比如说这次要分享的是绘制流程,就其控件类型而言分为View(无子View)和ViewGroup。那么正式开始吧:

何为绘制流程Android,用官方一点的话说就是测量(Measure)/布局(Layout)/绘制(Draw)的统称。用自己的话说就是把需要的界面显示在设备上即可。Activity作为
Android的一个载体存在,那么首先要知道Activity在Android中的UI层级关系:

Activity---->PhoneWindow---->DecorView---->Title View和Content View
1.先说Content View 就是我们在Activity调用setContentView方法的布局,所以方法叫setContentView是不是很好理解了。
2.PhoneWindow 是Activity最基本的窗口系统,每个Activity会创建一个。PhoneWindow是Android 和Activity的交互接口,DecorView是Activity的最顶层。(不理解也没有关系)

到现在为止为一小节,简单介绍了Android 整体绘制的一个轮廓。

下面开始从ViewRootImpl根视图的 performTraversals()方法开始说起,为什么是这个方法,那就要从启动Activity时的源码分析,我还没有彻底弄懂Activity的启动流程。就不扯远了。
在PerformTraversals中 分别让顺序调用了PerformMeasure/PerformLayout/PerformDraw方法。接下来分析者三个方法都做了什么。

performMeasure(1,2):

performMeasure是测量控件具体宽高(并不一定是实际宽高)
(在讲Measure测量的时候有个类是必须要弄懂的MeasureSpec,有关MeasureSpec重新写了一篇文章,就好比一个方法只做一件事。有关MeasureSpec类的介绍请看XXX(还没写,哈哈))
现在我们理解了MeasureSpec类,接下来看PerforemMeasure里有什么吧。其实就是调用了mView.measure(1,2) (1/2代表参数),此后不再介绍。然后看View类的measure(1,2)方法吧!

然而View的measure方法只是正对自身View的,所以我们要去ViewGroup开始找有关measure方法。我们发现ViewGroup方法里有个measureChildren(1,2)方法,会根据children(子View)的个数循环调用measureChild(1,2)方法,重新测量后(根据父的MeasureSpec和自身LayoutParams信息得出),又调用了View.measure方法。measure方法调用了自身的onMeasure方法,(这个就是我们自定义veiw重写onMeasure的方法),如果没有重写就会调用getDefaultSize来获取View 的宽高。这样在ViewGroup的measureChildren的for循环下就测量完所有View的宽高了。走势图来一波:
performMeasure—>veiw.measure(1,2)---->onMeasure(1,2)---->getDefaultSize(1.2)(默认)
ViewGroup—>measureChildren(1,2)–循环–>measureChild(1,2)—>veiw.measure(1,2)…

PS在整个measure期间,都有关于MeasureSpec测量的使用,所以要弄懂Measure(测量)首先要掌握MeasureSpec的用法!!!这里只是梳理了整个测量的流程,具体的测量并没有说明。(后续添加吧)

performLayout:

performLayout是用来确定View在父容器的布局位置,父容器获取子View的测量宽高参数(getMeasuredWidth/getMeasuredHeight),然后调用了View的layout方法,然后走了View的OnLayout方法,onLayout在View或者ViewGroup都是个空实现。在layout方法中确定自身的位置,而OnLayout是确定所有子View的位置。具体OnLayout的实现就要更具布局特性自己去实现,比如LinearLayout类中OnLayout就是根据横向/纵向分别确定布局位置。大概的思路就是:

ViewGroup.Onlayout()—循环---->View.layout方法.(确定自身布局的位置,传过来的参数就是measure测量的宽高)。

把握整体思路后,然后重写onLayout方法时就可以去参考已有控件的实现逻辑了。

performDraw:
最后就是ViewRootImpl中的performDraw方法,执行了ViewRootImpl.draw方法。
需要记住View.draw绘制到屏幕的具体步骤:

1.绘制背景 background.draw(canvas)
2.绘制自己(OnDraw)
3.绘制Children (dispatchDraw) —>ViewGroup
4.绘制装饰(onDrawScrollBars)

其中的精髓在于dispatchDraw方法,顶层是个View,执行到draw方法,然后到disparchDraw方法,disparchDraw遍历调用了View的draw方法,然后又执行了四大步来反复绘制所有View。最终经过measure测量和layout布局位置到draw绘制到屏幕上。

有没有发现一个规律:都是在ViewGroup中循环执行View中的方法(自己总结时发现的,就是所谓的指导思想吧)

关于自定义View,把握好整体流程再去写具体细节,就能做到知其所以然。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值