无论是在重写View还是ViewGroup的时候,尤其是ViewGrop的时候,往往不可避免的重写onMeasure方法,我们一定会调用setMeasuredDimension()将测量好的宽高值传递进去。也不免调用measureChildren方法,来测量所有的子View的大小,下面我们看看measureChildren方法是如何工作的。这对我们重写onMeasure无疑是很有帮助的。因为一般我们都会看到这一行代码

// 计算出所有的childView的宽和高measureChildren(widthMeasureSpec, heightMeasureSpec);

但 是它到底测量到什么程度,满足不满足我们自定义ViewGroup对下面一系列child尺寸的测量需求,不知道这个我们写代码就心里没底。所以我们有必 要扒出它的老底来看看,由此来决定我们是否可以直接使用这个方法,还是由于我们有更多的效果要实现,有更多的因素需要考虑,这个方法不能满足需求,需要自 己写方法来测量child。

同时我们在有必要重新写方法来测量child的时候,我们也要从自带方法的思路开始扩展。

说了一大堆,总之这个问题很重要。

下面要了解它的工作原理,我们还是要来看看源码

(一)首先是measureChildren

 /*** 遍历所有的子view去测量自己(跳过GONE类型View)* @param widthMeasureSpec 从父容器传递给子容器的布局需求(宽) * @param heightMeasureSpec 从父容器传递给子容器的布局需求(高) */protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {	final int size = mChildrenCount;	final View[] children = mChildren;	for (int i = 0; i < size; ++i) {		final View child = children[i];		if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {			measureChild(child, widthMeasureSpec, heightMeasureSpec);		}	}}

这部分很简单,也就是遍历所有的子View,如果View的状态不是GONE就调用measureChild去进行下一步的测量。

所以我们再来看一下measureChild

/*** 测量单个视图,将宽高和padding加在一起后交给getChildMeasureSpec去获得最终的测量值* @param child 需要测量的子视图 <pre name="code" class="java"> * @param widthMeasureSpec 从父容器传递给子容器的布局需求(宽) * @param heightMeasureSpec 从父容器传递给子容器的布局需求(高)

*/ protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { // 取得子视图的布局参数 final LayoutParams lp = child.getLayoutParams(); // 通过getChildMeasureSpec获取最终的宽高详细测量值 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); // 将计算好的宽高详细测量值传入measure方法,完成最后的测量 child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }

这个方法就是对一个子视图进行测量,其中一个重要的方法就是getChildMeasureSpec(),

(三)所以我们再来看一下getChildMeasureSpec

/**** 结合父view的MeasureSpec与子view的LayoutParams信息去找到最好的结果* (子view的确切大小由两方面共同决定:父view的MeasureSpec 子view的LayoutParams属性)* * @param spec 父view的MeasureSpec * @param padding view当前尺寸的的内边距和外边距(padding,margin)* @param childDimension child在当前尺寸下的布局参数宽高值(LayoutParam.width,height)*/public static int getChildMeasureSpec(int spec, int padding, int childDimension) {	//父view的模式和大小	int specMode = MeasureSpec.getMode(spec);	 	int specSize = MeasureSpec.getSize(spec);	 	//通过父view计算出的子view = 父大小-边距(父要求的大小,但子view不一定用这个值) 	int size = Math.max(0, specSize - padding);	//子view想要的实际大小和模式(需要计算)	int resultSize = 0;	int resultMode = 0;	//通过1.父view的MeasureSpec 2.子view的LayoutParams属性这两点来确定子view的大小	switch (specMode) {	// 当父view的模式为EXACITY时,父view强加给子view确切的值	case MeasureSpec.EXACTLY:		// 当子view的LayoutParams>0也就是有确切的值		if (childDimension >= 0) {			//子view大小为子自身所赋的值,模式大小为EXACTLY			resultSize = childDimension;			resultMode = MeasureSpec.EXACTLY;		// 当子view的LayoutParams为MATCH_PARENT时(-1)		} else if (childDimension == LayoutParams.MATCH_PARENT) {			//子view大小为父view大小,模式为EXACTLY			resultSize = size;			resultMode = MeasureSpec.EXACTLY;		// 当子view的LayoutParams为WRAP_CONTENT时(-2)			} else if (childDimension == LayoutParams.WRAP_CONTENT) {			//子view决定自己的大小,但最大不能超过父view,模式为AT_MOST			resultSize = size;			resultMode = MeasureSpec.AT_MOST;		}		break;	// 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。	case MeasureSpec.AT_MOST:		// 道理同上		if (childDimension >= 0) {			resultSize = childDimension;			resultMode = MeasureSpec.EXACTLY;		} else if (childDimension == LayoutParams.MATCH_PARENT) {			resultSize = size;			resultMode = MeasureSpec.AT_MOST;		} else if (childDimension == LayoutParams.WRAP_CONTENT) {			resultSize = size;			resultMode = MeasureSpec.AT_MOST;		}		break;	// 当父view的模式为UNSPECIFIED时,子view为想要的值	case MeasureSpec.UNSPECIFIED:		if (childDimension >= 0) {			// 子view大小为子自身所赋的值			resultSize = childDimension;			resultMode = MeasureSpec.EXACTLY;		} else if (childDimension == LayoutParams.MATCH_PARENT) {			// 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0			resultSize = 0;			resultMode = MeasureSpec.UNSPECIFIED;		} else if (childDimension == LayoutParams.WRAP_CONTENT) {			// 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0			resultSize = 0;			resultMode = MeasureSpec.UNSPECIFIED;		}		break;	}	return MeasureSpec.makeMeasureSpec(resultSize, resultMode);}

总而言之,这些判断和设置其实就是根据三种模式以及传入的尺寸要求,还有需要考虑的padding和margin之后,比较全面的计算出了一个测量值,了解了这些之后我们就可以确定什么时候需要自己写关于子视图的测量部分,什么时候我们只需要简单的一行代码:

// 计算出所有的childView的宽和高measureChildren(widthMeasureSpec, heightMeasureSpec);

就可以满足我们的需求了,所以一切还是按需来处理。

在我个人看来,这个方法考虑的比我最初想象的要全面多了,看来除了有比较特殊的需求,大部分的时候都是可以直接使用这个方法的。这还是省了不少事的。

如果您对我提到的模式或者是重写过程不大了解的,具体的关于重写onMeasure内容请详见我的另外一篇博客:

http://blog.csdn.net/sunmc1204953974/article/details/38454267

希望大家能有所收获,我也是学生,有什么写的不好的地方还请多多指教!

measureChildren的工作原理的更多相关文章

  1. 梳理源码中 View 的工作原理

    欢迎Follow我的GitHub, 关注我的掘金. 在View的工作过程中, 执行三大流程完成显示, 测量(measure)流程, 布局(layout)流程, 绘制(draw)流程. 从perform ...

  2. Android学习笔记View的工作原理

    自定义View,也可以称为自定义控件,通过自定义View可以使得控件实现各种定制的效果. 实现自定义View,需要掌握View的底层工作原理,比如View的测量过程.布局流程以及绘制流程,除此之外,还 ...

  3. Android艺术开发探索第四章——View的工作原理(下)

    Android艺术开发探索第四章--View的工作原理(下) 我们上篇BB了这么多,这篇就多多少少要来点实战了,上篇主席叫我多点自己的理解,那我就多点真诚,少点套路了,老司机,开车吧! 我们这一篇就扯 ...

  4. Android之view的工作原理2

    学习内容 View的底层工作原理,比如View的测量流程.布局流程以及绘制流程:以及常见的View回调方法:熟悉掌握前面的知识后,自定义View的时候也会更加的得心应手. 4.1 初识ViewRoot ...

  5. Android 中View的工作原理

    Android中的View在Android的知识体系中扮演着重要的角色.简单来说,View就是Android在视觉的体现.我们所展现的页面就是Android提供的GUI库中控件的组合.但是当要求不能满 ...

  6. [旧][Android] View 工作原理(二)

    备注 原发表于2016.05.27,资料已过时,仅作备份,谨慎参考 前言 本文大量参照<Android 开发艺术探索>及参考资料的内容整合,主要帮助自己理清 View 的工作原理.深入学习 ...

  7. 菜鸟学Struts2——Struts工作原理

    在完成Struts2的HelloWorld后,对Struts2的工作原理进行学习.Struts2框架可以按照模块来划分为Servlet Filters,Struts核心模块,拦截器和用户实现部分,其中 ...

  8. 【夯实Nginx基础】Nginx工作原理和优化、漏洞

    本文地址 原文地址 本文提纲: 1.  Nginx的模块与工作原理    2.  Nginx的进程模型    3 . NginxFastCGI运行原理        3.1 什么是 FastCGI   ...

  9. HashMap的工作原理

    HashMap的工作原理   HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间 ...

随机推荐

  1. 《锋利的JQuery》读书要点笔记1——认识JQuery&&选择器

    <锋利的jQuery>源码下载,包括了这本书中全部代码以及用到的CSS文件 第一章 认识jQuery jQuery是个Js库.首先该明确的一点是:在jQuery库中$就是jQuery的一个 ...

  2. poj 3254(状态压缩+动态规划)

    http://poj.org/problem?id=3254 题意:有一个n*m的农场(01矩阵),其中1表示种了草可以放牛,0表示没种草不能放牛,并且如果某个地方放了牛,它的上下左右四个方向都不能放 ...

  3. linux下IPTABLES配置详解 (防火墙命令)

    linux下IPTABLES配置详解 -A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 24000 -j ACCEPT ...

  4. 线段树维护矩阵【CF718C】 Sasha and Array

    Description 有一个长为\(n\)的数列\(a_{1},a_{2}...a_{n}\),你需要对这个数列维护如下两种操作: \(1\space l \space r\space x\) 表示 ...

  5. 【树状数组】bzoj2743 [HEOI2012]采花

    http://www.cnblogs.com/proverbs/archive/2012/10/29/2745281.html (↑)这样处理之后,每次询问时,对于每种颜色,从1到其倒数第二次出现的位 ...

  6. Problem G: 零起点学算法27——等级分制度

    #include<stdio.h> int main() { int a,b; while(scanf("%d %d",&a,&b)!=EOF) +a* ...

  7. Python学习实践 | speech智能语音模块

    最近的生活.学习节奏很是容易被打断,终于,在今天,既实习结束之后,夏令营也结束了. 前几天,一个人在复习地很累的时候,又重新将Python捡了起来,看了挺多的知识点. 真是太有意(wu)思(liao) ...

  8. iOS开发——Autolayout下动态调整单元格高度

    情景描述: 有时候我们希望更新某一个单元格的数据,通常的做法是使用reloadData方法更新整个单元格.但是对一些情况是不适用的或者说实现起来比较麻烦.比如说这种简单的"点开"一 ...

  9. Xcode8 不能显示blame,show blame for line 灰色不可点解决办法

    1.原因 创建工程时没勾选create git repository 2.解决办法 ➜  ~  cd /Users/zhanglinfeng/Documents/EastMoney/EMLive  / ...

  10. Bootstrap响应式布局

    Bootstrap响应式布局可以使用栅格化系统,其实就是不同的列组合,配合起来便能组合出强大的功能,系统会自动分为最多12列,超出12列会作为一个整体另起一行,像制作表格table的合并列,功能跟co ...