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
- 绘制背景
- 绘制自己
- 绘制子view
- 绘制装饰