view绘制过程笔记

view绘制过程

绘制过程由Viewroot的perfortraversals 开始依次调用performMeasure,performlayout,performondraw,performMeasure回调用onmeasure方法,ommeasure方法会遍历子view,依次调用measure,子view也会重复这个动作,onlayout,ondraw也和这个一样

view的measure

MeasureSpec

由两部分组成,size,mode

  • EXACYLY 父类已经检测出大小,就是size
  • AT_MOST 指定一个值(size),子view的宽高不超过这个值(size)
  • UNSPECFIED 不限制大小,随便多大

父view创建子view的MeasureSpec规则

  • 如果view是固定宽高,不管父viewgroup是什么,都是EXACTLY,size就是父view的剩余宽高
  • 如果view是match_parent,父容器是EXACTLY,子view也是EXACTLY,宽高就是父容器剩余宽高,父容器是AT_MOST,子view就是AT_MOST,宽高不超过父容器剩余宽高
  • 如果view是wrap_content,不管父容器什么模式,他都是AT_MOST,并且宽高都是父容器的剩余宽高

父view在测量的时候会遍历子view,根据自身的specMode,和view的layoutparms根据上面规则来获得子view的MeasureSpec

View测量过程

在onmesure中根据MeasureSpec参数来调用setmeasureDimension()方法设置宽高

  • EXACYLY 直接设置Size为宽高
  • AT_MOST 直接设置Size为宽高
  • UNSPECFIED 根据minwidth(view属性)和background宽高,谁大用谁的

因为AT_MOST中的Size是父view的剩余宽高,直接用的话和match_parent效果一样,所以我们需要自己处理一下,一般是先设定一个默认宽高,判断如果是AT_MOST模式就设置默认的宽高

viewgroup由于不同的容器,子view排列的位置也不确定,所以onmeasure方法是自己实现,如果是EXACTLY测量过程和view一样,如果是AT_MOST,linearlayout会根据方向的不同测量时会遍历子view,把高度或者宽度累加,就是linearlayout宽高了

Measure(0,0)

view调用measure(0,0)的时候实际上是调用告诉view使用UNSPECFIED模式来测量,就是你本来就多大就多大,没有限制,实际上就是 minwidth(view属性值)和minBackground的最大值,textview就是内容实际高度,getmeasurewidth拿到的值跟xml中width,height无关,所以在wrap_content的时候用measure(0,0)才可能是准的,内容超过父view剩余高度的话,也会不准

layout

layout 和 onlayout

layout是确定自己的位置调用setfram来确定了自己的位置,然后调用onlayout,在view中是空实现,每个viewgroup都有自己的实现,基本就是遍历子view然后根据自己的规则来确定每个子view的位置

在linearlayout中会根据方向来把宽或者高累加,然后遍历调用子view的layout,

getwidth 和getmeasurewidth区别就是一个是在onmeasure中赋值的一个是在layout中赋值的,如果view没有重写layout两个值就是相等的

draw

  1. 绘制背景
  2. 绘制自己
  3. 绘制子view
  4. 绘制装饰

猜你喜欢

转载自blog.csdn.net/m0_37546888/article/details/84969968