View的工作流程
2016-04-27 20:43
197 查看
View的工作流程主要是指measure、layo
4000
ut、draw三大流程,即测量、布局、绘制,其中measure确定View的测量宽高,layout确定View的最终宽高和四个顶点的位置,而draw则将View绘制到屏幕上。
View的measure过程
View的measure过程由其measure方法完成,measure方法是一个final类型的方法,这意味着子类不能重写此方法,在View的measure方法中回去调用View的onMeasure方法,因此只需要看OnMeasure的实现即可。
setMeasuredDimension方法会设置View宽高的测量值,因此我们只需要看getDefaultSize这个方法即可:
这个方法返回值的大小就是measureSpec中的specSize,而这个specSize就是View测量后的大小,这里多次提到测量后的大小,是因为View的最终大小是在layout阶段确定的,所以这里必须要区分,但是几乎所有的情况下View的测量大小和最终大小是相等的。
ViewGroup的measure过程
对于ViewGroup来说,除了完成自己的measure过程外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个过程。和View不同的是,ViewGroup是一个抽象类,因此他没有重写View的onMeasure方法,但是它提供了一个叫measureChildren的方法
ViewGroup在measure时,会对每一个子元素进行measure
measureChild就是取出子元素的LayoutParams,然后再通过getChildMeasureSpec来创建子元素的MeasureSpec,接着将MeasureSpec传递给View的measure方法来进行测量。
ViewGroup没有定义其测量的具体过程,因为ViewGroup是一个抽象类,其测量过程的onMeasure方法需要各个子类去具体实现,比如LinearLayout、RelativeLayout等,因为不同的ViewGroup有不同的布局特性,这导致他们的测量细节各不相同。
以LinearLayout为例:
先来看它的onMeasure方法
上述代码为水平或竖直布局的选择
measureVertical方法中,系统会遍历子元素并对每个子元素执行measureChildBeforeLayout方法,这个方法内部会调用子元素的measure方法,这样各个子元素就开始依次进入measure过程,并且系统会通过mTotalLength这个变量来存储LinearLayout在竖直方向的初步高度。每测量一个子元素,mTotalLength都会增加,增加的部分主要包括了子元素的高度以及子元素在竖直方向上的margin等。当子元素测量完毕后,LinearLayout会测量自己的大小。
这个方法的含义是:View已经初始化完毕了,宽高已经准备好了。需要注意的是当Activity的窗口得到焦点和失去焦点的时候均会被调用一次。具体来说如果频繁的进行onResume和onPause,那么onWindowFocusChanged也会被频繁的调用。
view.post(runnable)
通过post也可以讲一个runnable投递到消息队列的尾部,然后等待Loop而调用此runnable的时候,View也已经初始化好了
3.ViewTreeObserve
使用ViewTreeObserve的众多回调可以完成这个功能,比如使用OnGlobalLayoutListener这个借口,当View树的状态发生改变或者View树内部的View的可见性发生改变时,onGlobalLayout方法将会被回调,因此这是获取View的宽高一个很好的时机。需要注意的是,伴随着View树的状态改变等,onGloableLayout会被调用多次。
4.view.measure(int widthMeasureSpec,int heightMeasureSpec)
通过手动对View进行measure来得到View的宽高。这种要分情况处理,根据View的LayoutParams来分:
match_paent
直接放弃,无法measure出具体的宽高。原因很简单,根据View的measure过程,构造此种MeasureSpec需要知道parentSize,而这个时候我们无法知道parentSize的大小,所以理论上不可能测量出View的大小。
具体的数值
比如宽高都是100px:
warp_content
(1<<30)-1,View的尺寸使用30位二进制表示,也就是说最大是30个1,也就是(1<<30)-1在最大模式下,我們用View理論上能支持最大的值去構造MEasureSpec。
4000
ut、draw三大流程,即测量、布局、绘制,其中measure确定View的测量宽高,layout确定View的最终宽高和四个顶点的位置,而draw则将View绘制到屏幕上。
measure过程
该过程需要分情况来看,如果是一个原始的View,那么通过measure方法就可以完成其测量过程,如果是一个ViewGroup,除了完成自己的测量过程,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个过程。View的measure过程
View的measure过程由其measure方法完成,measure方法是一个final类型的方法,这意味着子类不能重写此方法,在View的measure方法中回去调用View的onMeasure方法,因此只需要看OnMeasure的实现即可。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
setMeasuredDimension方法会设置View宽高的测量值,因此我们只需要看getDefaultSize这个方法即可:
public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
这个方法返回值的大小就是measureSpec中的specSize,而这个specSize就是View测量后的大小,这里多次提到测量后的大小,是因为View的最终大小是在layout阶段确定的,所以这里必须要区分,但是几乎所有的情况下View的测量大小和最终大小是相等的。
ViewGroup的measure过程
对于ViewGroup来说,除了完成自己的measure过程外,还会遍历去调用所有子元素的measure方法,各个子元素再递归去执行这个过程。和View不同的是,ViewGroup是一个抽象类,因此他没有重写View的onMeasure方法,但是它提供了一个叫measureChildren的方法
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); } } }
ViewGroup在measure时,会对每一个子元素进行measure
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec);protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } }
measureChild就是取出子元素的LayoutParams,然后再通过getChildMeasureSpec来创建子元素的MeasureSpec,接着将MeasureSpec传递给View的measure方法来进行测量。
ViewGroup没有定义其测量的具体过程,因为ViewGroup是一个抽象类,其测量过程的onMeasure方法需要各个子类去具体实现,比如LinearLayout、RelativeLayout等,因为不同的ViewGroup有不同的布局特性,这导致他们的测量细节各不相同。
以LinearLayout为例:
先来看它的onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == VERTICAL) { measureVertical(widthMeasureSpec, heightMeasureSpec); } else { measureHorizontal(widthMeasureSpec, heightMeasureSpec); } }
上述代码为水平或竖直布局的选择
measureVertical方法中,系统会遍历子元素并对每个子元素执行measureChildBeforeLayout方法,这个方法内部会调用子元素的measure方法,这样各个子元素就开始依次进入measure过程,并且系统会通过mTotalLength这个变量来存储LinearLayout在竖直方向的初步高度。每测量一个子元素,mTotalLength都会增加,增加的部分主要包括了子元素的高度以及子元素在竖直方向上的margin等。当子元素测量完毕后,LinearLayout会测量自己的大小。
获取View的宽高
onWindowFocusChanged:这个方法的含义是:View已经初始化完毕了,宽高已经准备好了。需要注意的是当Activity的窗口得到焦点和失去焦点的时候均会被调用一次。具体来说如果频繁的进行onResume和onPause,那么onWindowFocusChanged也会被频繁的调用。
view.post(runnable)
通过post也可以讲一个runnable投递到消息队列的尾部,然后等待Loop而调用此runnable的时候,View也已经初始化好了
protected void onStart() { // TODO Auto-generated method stub super.onStart(); view.post(new Runnable() { @Override public void run() { int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); } }); }
3.ViewTreeObserve
使用ViewTreeObserve的众多回调可以完成这个功能,比如使用OnGlobalLayoutListener这个借口,当View树的状态发生改变或者View树内部的View的可见性发生改变时,onGlobalLayout方法将会被回调,因此这是获取View的宽高一个很好的时机。需要注意的是,伴随着View树的状态改变等,onGloableLayout会被调用多次。
protected void onStart() { // TODO Auto-generated method stub super.onStart(); ViewTreeObserver observer = view.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeGlobalOnLayoutListener(this); int wigth = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); } }); }
4.view.measure(int widthMeasureSpec,int heightMeasureSpec)
通过手动对View进行measure来得到View的宽高。这种要分情况处理,根据View的LayoutParams来分:
match_paent
直接放弃,无法measure出具体的宽高。原因很简单,根据View的measure过程,构造此种MeasureSpec需要知道parentSize,而这个时候我们无法知道parentSize的大小,所以理论上不可能测量出View的大小。
具体的数值
比如宽高都是100px:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY); view.measure(widthMeasureSpec, heightMeasureSpec);
warp_content
int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.EXACTLY); int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.EXACTLY); view.measure(widthMeasureSpec, heightMeasureSpec);
(1<<30)-1,View的尺寸使用30位二进制表示,也就是说最大是30个1,也就是(1<<30)-1在最大模式下,我們用View理論上能支持最大的值去構造MEasureSpec。
相关文章推荐
- CodeForces - 236B Easy Number Challenge (暴力)
- 括号配对问题
- Unity项目中UI美术必须知道的程序要点
- RIP动态路由的配置命令(拓扑图)
- 出差(2~二十)
- 超炫的HTML5粒子效果进度条 VS 如何规范而优雅地code
- 旧手机作为USB无线网卡使用(分享WIFI、蓝牙连接)
- leetcode-88. Merge Sorted Array
- [转]iphone不越狱抓包
- openCV中图像间的加减乘除运算
- 虚拟机安装VMware-tools
- 直接插入排序
- C++用new来创建对象和非new来创建对象的区别
- 数据结构 - 线性表的顺序实现
- servlet--百度百科
- 漫画城之搜索
- Exception
- FileChannel
- python格式化dict输出
- 1015. Reversible Primes (20)