View系统启动measure是从ViewRoot中调用host.measure()开始, 过程如图 : [书本:P299]
host一般情况下是ViewGroup的实例,会在onMeasure()中对所包含的子视图逐一进行measure(),为了简化程序官方提供了一个 measureChildWithMargins()来自动对子视图进行measure(),如果子视图是个ViewGroup则会再次进行一次递归.
View的measure函数的原形是:
public final void measure(int widthMeasureSpec , int heightMeasureSpec);
SpecMode分三种:
①:MeasureSpec.EXACTLY : "确定的" , 意思是:父视图希望子视图的大小应该是specSize中指定.
②:MeasureSpec.AT_MOST: "最多" ,意思是 : 子视图的大小最多是specSize中指定的值.
③:MeasureSpec.UNSPECIFIED : "没有限制" 意思是 : 此时View设计者可以根据自身的特性设定大小
上面的MeasureSpec是由父视图传递给子视图的,那么最根部的MeasureSpec是怎么产生的呢?
就是在ViewRoot 的 host.measure() 函数时,获取到的屏幕宽高进行的设定.
假设根布局也制定了特定的宽高,host.measure()还是根据Spec来获取屏幕宽高进行设定.因为布局最后的宽高是由父布局和字布局共同决定的,而不是单方面决定的.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ViewGroup中的measureChildMargins()
1:measureChildren() : 该函数内部使用for()调用measureChild()对每一个子视图进行measure()
2:measureChild() : 为指定的子视图进行measure()
3:measureChildWithMargins() : 该函数与measureChild的唯一区别在于,measure时考虑把margin和padding 也作为子视图大小的一部分 .
创建View一般分两种
①XML定义 然后布局填充
②代码生成 然后Add
对于第一种实际上是内部进行了②的操作,当通过getSystemService()获取到inflater对象的时候第一个参数指定布局文件 第二个参数指定该View的父视图(一般为空)
而在XML中则使用具体标签来表示一个View,比如LinearLayout标签表示一个LinearLayout对象.
<以 measureChildWithMargins() 为例讲解>
而在inflate()内部会根据这些标签来进行②的操作动态生成视图对象,创建好后,此时对象内部的LayoutParams属性是空的.所有的View对象想要被显示到屏幕上,必须先调用addView()方法把View添加到当前窗口的View树中.
在该段代码中,由于Child当前的LayoutParams是空的所以会走 1825行 来生成一个LayoutParams对象.所有的ViewGroup基本都会重载该对象.比如LinearLayout就重载了并返回了一个LinearLayout.LayoutParams对象
PS:如果你自己写一个ViewGroup而不重载geneareDeafaultLayouParams()
那么程序在向你定义的这个ViewGroup中添加View的时候,将使用ViewGroup中默认的ViewGroup.LayoutParams,这将导致在XML中定义的margin属性无效.
且不能在自定义的ViewGroup中使用measureChildWithMargin(),而只能使用mesureChild() 否则会因为强制类型转换错误而发生异常
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
LinearLayout中的onMeasure()过程举例:
( View系统中的measure()必须由相应的ViewGroup实例共同参与才能完成一个真正的measure() )
下一节:权重的先后显示问题