1 :
1:父View会遍历测量每一个子View(通常使用ViewGroup类的measureChildWithMargins方法),然后调用子View的measure方法并且将测量后的宽高作为measure方法的参数,但是这只是父View的建议值,子View可以通过继承onMeasure来改变测量值。
(在上一篇文章已经有伪代码实现)
2:ViewGroup类型的View自身的测量是在ViewGroup类型的View的onMeasure方法中进行测量的(比如LinearLayout)
它实现了这么几个功能 :
2.1 遍历子控件的尺寸并累积加上margin尺寸,分割线等并作为成员变量保存(measureChildWithMargins() 函数的 totalLength变量)
2.2 完成子控件测量之后,通过 将父控件自身测量的尺寸保留起来。
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), heightSizeAndState);
2.2.1 :resolveSizeAndState() 函数 作用:修正父控件测量侧尺寸,当 父控件是配置的是 wrap_content 时,
它的高度不能超出 剩余的空间 。
2.2.2 : measureChildWithMargins() 函数需要调用 getChildMeasureSpec() 函数返回的子元素MeasureSpec与父容器的MeasureSpec、父容器的padding、子元素的margin和兄弟元素占用的长度有关
final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin, lp.width);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
getChildMeasureSpec() 函数实现可以抽象为下面的关系
3:所以,如果你自定义控件继承ViewGroup 就必须实现onMeasure()函数,否则会有异常(是不是以前碰到过 )
当配置的是 wrap_content时,需要注意给一个尺寸我。否则就相当于配置match_parent (上篇文章已经解释了)
源码实现+ 伪代码实现 :
5: 下面介绍下 :MeasureSpec (伪代码实现)
MeasureSpec 其实就是尺寸和模式通过各种位运算计算出的一个整型值,它提供了三种模式,还有三个方法(合成约束、分离模式、分离尺寸)-----后面再补充自己个人理解
总结 :
1:测量控件大小是父控件发起的,View控件直接通过onMeasue来测量自己,ViewGroup控件,没有onMeasue(),需要重写onMeasue函数,并做一系列操作,回调至View测量流程
2:父控件要测量子控件大小,需要重写onMeasure()方法,然后调用measureChildWithMargin(),并且需要通过 getChildMeasureSpec()函数获取子控件的 测量策略,最后设置给onMeasure()方法中
onMeasure()方法的参数是通过getChildMeasureSpec生成的
3 :如果我们自定义控件需要使用wrap_content,我们需要重写onMeasure()方法,并且注意要自己设置一个尺寸值
4:测量控件的步骤:
父控件onMeasure-----> measureChildWithMargin----> getChildMeasureSpec----> 子控件的measure-----> onMeasure----> setMeasureDimension-----> 父控件测量子控件onMeasure结束调用-----》setMeasureDimension`保存自己的大小