View和ViewGroup 的measure过程

本文详细解析了Android中View和ViewGroup的测量流程,包括measure过程中的关键方法如onMeasure()、setMeasuredDimension()等,并探讨了MeasureSpec的作用及其与LayoutParams的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

View和ViewGroup 的measure过程

视图有3大流程,measure,layout,draw,即测量,布局和绘制.我们先分析第一个流程measure.

1.View 的measure过程

View 的measure过程是由其measure()来完成,这个方法是final类型的,也就是不能被之类重写,同时measure()会转调onMeasure(),所以我们暂时重点关注onMeasure()就可以了.实际我们在自定义一个视图控件的时候也是重写onMeasure方法.
   
   
  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  2. setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
  3. getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
  4. }
上面的方法就是调用了setMeasuredDismension()来设置mMeasuredWidth和mMeasuredHeight,这2个变量会在View 的layout 流程和draw流程用到.但是在调用 setMeasuredDismension 时它的参数是由 getDefaultSize ()来得到的.具体源码如下:
   
   
  1. public static int getDefaultSize(int size, int measureSpec) {
  2. int result = size;
  3. int specMode = MeasureSpec.getMode(measureSpec);
  4. int specSize = MeasureSpec.getSize(measureSpec);
  5. switch (specMode) {
  6. case MeasureSpec.UNSPECIFIED:
  7. result = size;
  8. break;
  9. case MeasureSpec.AT_MOST:
  10. case MeasureSpec.EXACTLY:
  11. result = specSize;
  12. break;
  13. }
  14. return result;
  15. }
  16. protected int getSuggestedMinimumWidth() {
  17. return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth());
  18. }
其中getDefaultSize就是根据View 的MeasureSpec和另一个参数size来获取返回值.
其中我们需要关注的是 MeasureSpec.AT_MOST和MeasureSpec.EXACTLY2种模式,也就是都返回specSize.这个specSize也就是由由父容器的MeasureSpec和View自身的LayoutParams共同生成的View的MeasureSpec调用getsize得到的大小,可以理解为View 的测量之后得到的宽高大小.
上面另外一种模式 MeasureSpec . UNSPECIFIED ,是用来系统内部测量的.这种情况下返回值是size,也就是的 getSuggestedMinimumWidth和 getSuggestedMinimumHeight 返回值大小.
getSuggestedMinimumWidth()源码 可以得出结论:如果View没有设置背景,View 的宽度就是android:minWidth的值,如果没有设置这个值就是0,如果设置了背景,就是 android:minWidth和背景图标的宽度的较大值.

2.ViewGroup 的measure过程

由于 measure不能被重写,而且ViewGroup没有重写onMeasure(),所以是通过其他方法来处理这个measure流程.实际是使用的measureChildren().
ViewGroup.java
   
   
  1. protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
  2. final int size = mChildrenCount;
  3. final View[] children = mChildren;
  4. for (int i = 0; i < size; ++i) {
  5. final View child = children[i];
  6. if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {//是否可见
  7. measureChild(child, widthMeasureSpec, heightMeasureSpec);
  8. }
  9. }
  10. }
  11. protected void measureChild(View child, int parentWidthMeasureSpec,
  12. int parentHeightMeasureSpec) {
  13. final LayoutParams lp = child.getLayoutParams();
  14. final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
  15. mPaddingLeft + mPaddingRight, lp.width);
  16. final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
  17. mPaddingTop + mPaddingBottom, lp.height);
  18. child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
  19. }

上面的代码就是循环调用child view 的measure()方法,如果child view 也有child,那么就会递归执行这个measureChildren().
其中getChildMeasureSpec ()之前已经笔记"View MeasureSpec 和LayoutParams关系 "里面分析过,这里就重复分析.
所以我们可以知道ViewGroup没有执行具体的测量过程,只是调用child view 的measure()方法.这是因为ViewGroup类太多,不好统一处理.实际是各个子类去重写onMeasure来自己处理的.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值