Android中measure过程、WRAP_CONTENT详解以及xml布局文件解析流程浅析(上)
本文原创, 转载请注明出处:http://blog.csdn.net/qinjuning
在之前一篇博文中<< Android中View绘制流程以及invalidate()等相关方法分析>>,简单的阐述 了Android View
绘制流程的三个步骤,即:
1、 measure过程 --- 测量过程
2、layout 过程 --- 布局过程3、draw 过程 --- 绘制过程
要想对Android 中View这块深入理解,对这三个步骤地学习是必不可少的 。
今天,我着重讲解下如下三个内容:
1、 measure过程
2、WRAP_CONTENT、MATCH_PARENT/FILL_PARENT属性的原理说明
3、xml布局文件解析成View树的流程分析。
希望对大家能有帮助。- - 分析版本基于Android 2.3 。
1、WRAP_CONTENT、MATCH_PARENT/FILL_PARENT
初入Android殿堂的同学们,对这三个属性一定又爱又恨。爱的是使用起来挺爽地---照葫芦画瓢即可,恨的
却是时常混淆这几个属性地意义,需要三思而后行。在带着大家重温下这几个属性的用法吧(希望我没有嗦)。
这三个属性都用来适应视图的水平或垂直大小,一个以视图的内容或尺寸为基础的布局比精确地指定视图范围
更加方便。
① fill_parent设置一个视图的布局为fill_parent将强制性地使视图扩展至父元素大小。
② match_parent
Android 中match_parent和fill_parent意思一样,但match_parent更贴切,于是从2.2开始两个词都可以
用,但2.3版本后建议使用match_parent。
③ wrap_content
自适应大小,强制性地使视图扩展以便显示其全部内容。以TextView和ImageView控件为例,设置为
wrap_content将完整显示其内部的文本和图像。布局元素将根据内容更改大小。
可不要重复造轮子,以上摘自<<Android fill_parent、wrap_content和match_parent的区别>>。
当然,我们可以设置View的确切宽高,而不是由以上属性指定。
该类图是在太庞大了,大家有兴趣的去看看Android API吧。
前面我们说过,每个View都包含一个ViewGroup.LayoutParams类或者其派生类,下面我们的疑问是Android框架
中时如何为View设置其LayoutParams属性的。
有两种方法会设置View的LayoutParams属性:
1、直接添加子View时,常见于如下几种方法:ViewGroup.java
inflate public View inflate (int resource, ViewGroup root)public View inflate (int resource, ViewGroup root, boolean attachToRoot)
这三个类主要迷惑之处在于地三个参数attachToRoot,即是否将该View树添加到root中去。具体可看这篇博客:
<<关于inflate的第3个参数>>
当然还有LayoutInflater的inflate()的其他重载方法,大家可以自行了解下。
我利用下面的例子给大家走走这个流程 :
public class TypedArray {.../** * Special version of {@link #getDimensionPixelSize} for retrieving * {@link android.view.ViewGroup}'s layout_width and layout_height * attributes. This is only here for performance reasons; applications * should use {@link #getDimensionPixelSize}. * * @param index Index of the attribute to retrieve. * @param name Textual name of attribute for error reporting. * * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels. */ public int getLayoutDimension(int index, String name) { index *= AssetManager.STYLE_NUM_ENTRIES; final int[] data = mData; //获得属性对应的标识符 , Identifies,目前还没有仔细研究相关类。 final int type = data[index+AssetManager.STYLE_TYPE]; if (type >= TypedValue.TYPE_FIRST_INT && type <= TypedValue.TYPE_LAST_INT) { return data[index+AssetManager.STYLE_DATA]; } else if (type == TypedValue.TYPE_DIMENSION) { //类型为dimension类型 return TypedValue.complexToDimensionPixelSize( data[index+AssetManager.STYLE_DATA], mResources.mMetrics); } //没有提供layout_weight和layout_height会来到此处 ,这儿会报异常! //因此布局文件中的View包括自定义View必须加上属性layout_weight和layout_height。 throw new RuntimeException(getPositionDescription() + ": You must supply a " + name + " attribute."); }...}
从上面得知, 我们将View的AttributeSet属性传递给generateLayoutParams()方法,让其构建合适地LayoutParams对象,并且初始化属性值weight和height。同时我们也得知 布局文件中的View包括自定义View
必须加上属性layout_weight和layout_height,否则会报异常。
Step 3 主要做了如下事情:
首先,获得了了布局文件地root View,即布局文件中最顶层的View。其次,通过递归调用,我们形成了整个View树以及设置了每个View的LayoutParams对象。
总结:通过对布局文件的解析流程的学习,也就是转换为View树的过程,我们明白了解析过程的个中奥妙,以及
设置ViewLayoutParams对象的过程。但是,我们这儿只是简单的浮光掠影,更深层次的内容希望大家能深入学习。
本来是准备接下去往下写的,但无奈贴出来的代码太多,文章有点长而且自己也有点凌乱了,因此决定做两篇
博客发表吧。下篇内容包括如下方面:
1、MeasureSpec类说明 ;
2、measure过程中如何正确设置每个View的长宽 ;
3、UI框架正确设置顶层View的LayoutParams对象,对Activity而言,顶层View则是DecorView,
其他的皆是普通View了。