Android进阶系列0—View的工作流程:measure,layout,draw小结
2016-08-05 19:49
543 查看
本文主要来自《Android开发艺术探索》和郭霖 《Android视图绘制流程完全解析,带你一步步深入了解View(二)》 两部分的综合理解。
本文只阐述流程,不讲述细节,大家可以结合上述两部分的细节看。如有问题,欢迎大家在评论区指出,谢谢!
View由ViewRoot完成三大流程。在ActivityThread中,当Activity对象被创建完毕后,DecorView会被添加到Window中,同时创建ViewRootImpl的对象,将其和DecorView关联。
View的绘制流程由ViewRoot的performTraversals()方法调用performMeasure,performLayout,performDraw完成顶级View(即DecorView)的measure,layout,draw。
measure()方法内调用onMeasure()方法处理MeasureSpec参数
onMeasure()中再调用setMeasuredDimension()方法去设置View的具体宽高值
宽高值由getDefaultSize()方法将传入的MeasureSpec处理后得到(对于UNSPECIFIED这种情况,宽高值还与getSuggestedMinimumWidth等参数有关,由于这种SPEC_MODE很少用,这里不做讨论)
上述流程代码结构如下:
说完ViewGroup measure时的共有方法,再看看需要各自实现的onMeasure(),比如在LinearLayout中,onMeasure的实现大致如下:
至此,measure的过程就说完了。对于View来说,调用自身的measure()方法即可;对于ViewGroup,遍历调用所有子布局的measure方法后,在自定义的onMeasure()方法中得到ViewGroup的measure值。
还是参考LinearLayout的代码:
这样,layout的过程也分析完了,总的来说过程就是,使用layout确定完自己的布局之后,就调用onLayout确定子布局的位置(View的onLayout方法就是空方法)。
1. 绘制背景
2. 绘制自己(onDraw)
3. 绘制children(dispatchDraw)
4. 绘制装饰
每个视图的内容部分肯定都是不相同的,所以View的onDraw()是空方法,这部分的功能交给子类来去实现。
第四步的作用是对当前视图的所有子视图进行绘制。但如果当前的视图没有子视图,那么也就不需要进行绘制了。因此你会发现View中的dispatchDraw()方法又是一个空方法。
乌啦啦,View的工作流程就说完了,谢谢观看!有问题请留言,欢迎讨论~
方法论就这些,后面博主会放一个Github的demo链接,有兴趣的小伙伴可以瞅瞅。to be continued…
本文只阐述流程,不讲述细节,大家可以结合上述两部分的细节看。如有问题,欢迎大家在评论区指出,谢谢!
View由ViewRoot完成三大流程。在ActivityThread中,当Activity对象被创建完毕后,DecorView会被添加到Window中,同时创建ViewRootImpl的对象,将其和DecorView关联。
View的绘制流程由ViewRoot的performTraversals()方法调用performMeasure,performLayout,performDraw完成顶级View(即DecorView)的measure,layout,draw。
measure
View的measure要分View和ViewGroup两种情况考虑,对于View我们可以给出通用的measure()方法,但是不同的ViewGroup(指ViewGroup的具体实现类,比如LinearLayout,RelativeLayout等)需求不一样,measure的过程不尽相同,所以ViewGroup给出了可以共用的方法,如measureChildren(),measureChild()等,留出了各ViewGroup实现类自行编写的抽象方法onMeasure()。View的measure
View的对象调用measure()方法处理传入的MeasureSpec参数(这个参数比较好懂,就不解释了)measure()方法内调用onMeasure()方法处理MeasureSpec参数
onMeasure()中再调用setMeasuredDimension()方法去设置View的具体宽高值
宽高值由getDefaultSize()方法将传入的MeasureSpec处理后得到(对于UNSPECIFIED这种情况,宽高值还与getSuggestedMinimumWidth等参数有关,由于这种SPEC_MODE很少用,这里不做讨论)
上述流程代码结构如下:
public final void measure(int widthMeasureSpec, int heightMeasureSpec) { ... @Override onMeasure(widthMeasureSpec, heightMeasureSpec); ... } protected void onMeasure(int widthMeasureSpec,int heightMeasureSpec){ setMeasuredDimension(getDefaultSize(...),...); }
ViewGroup的measure
ViewGroup的measure与它自身的布局特性及内部的子布局有关。也就是说ViewGroup在measure自己的时候,需要先完成子布局的measure,然后再结合自己的特性(比如竖直,水平等)给出自身的measure值。所以,对于ViewGroup类来说,抽象出了几个通用的方法,完成子布局measure的:measureChildren(),measureChild(),getChildMeasureSpec()等。而特性相关的给出了一个抽象方法onDraw(),由各个ViewGroup的实现类自行重写。/* *遍历当前布局下的所有子视图,然后逐个调用measureChild()方法来测量相应子视图的大小 */ 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); } } } /* *measueChild()中,调用getChildMeasureSpec()方法去计算子视图的MeasureSpec,并将MeasureSpec传入child.measure()对View设置 */ protected void measureChild(View child,int parentWidthMeasureSpec,int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(...); final int childHeightMeasureSpec = getChildMeasureSpec(...); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
说完ViewGroup measure时的共有方法,再看看需要各自实现的onMeasure(),比如在LinearLayout中,onMeasure的实现大致如下:
/* *按方向选择函数 */ protected void onMeasure(int widthMeasureSpec,int heigthMeasureSpec){ if(mOrientation==VERTICAL){ measureVertical(); }else{ measureHorizontal(); } } /* 对水平LinearLayout布局来说,调用了*measureChildBeforeLayout()方法,并在函数末尾调用了setMeasuredDimension()设置LinearLayout的measure值 */ void measureHorizontal(int widthMeasureSpec, int heightMeasureSpec) { ...... measureChildBeforeLayout(); ...... setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), heightSizeAndState); ...... } /* *measureChildWithMargins是在ViewGroup中定义的measure通用方法,和measureChild的不同之处在于多考虑了margin等属性对测量的影响 */ void measureChildBeforeLayout(......) { measureChildWithMargins(......); }
至此,measure的过程就说完了。对于View来说,调用自身的measure()方法即可;对于ViewGroup,遍历调用所有子布局的measure方法后,在自定义的onMeasure()方法中得到ViewGroup的measure值。
layout
对于layout,View中给出了layout()方法用于设定View相对于父布局的位置。对于ViewGroup,设置完自己的位置后(ViewGroup本身相对于父布局的位置),怎也也得去布局子视图的位置吧。onLayout()方法就应运而出,用于确定父布局中子视图的位置。可以这么理解,onLayout()是控件留出来的编程接口方法,给View和ViewGroup的子类继承,当然,因为View不存在子布局,所以View的onLayout()方法为空方法,而在ViewGroup中,类似于measure时,不同的ViewGroup实现类的布局结构不同,onLayout()由各实现类自行重写。还是参考LinearLayout的代码:
/* *LinearLayout重写的onLayout方法 */ protected void onLayout(boolean changed, int l, int t, int r, int b) { if (mOrientation == VERTICAL) { layoutVertical(l, t, r, b); } else { layoutHorizontal(l, t, r, b); } } /* *遍历所有子布局并调用setChildFrame设定布局位置 */ void layoutHorizontal(int left, int top, int right, int bottom) { ...... for (int i = 0; i < count; i++) { int childIndex = start + dir * i; final View child = getVirtualChildAt(childIndex); ...... setChildFrame(child, childLeft + getLocationOffset(child), childTop, childWidth, childHeight); ...... } } /* *调用child.layout设定子布局位置 */ private void setChildFrame(View child, int left, int top, int width, int height) { child.layout(left, top, left + width, top + height); }
这样,layout的过程也分析完了,总的来说过程就是,使用layout确定完自己的布局之后,就调用onLayout确定子布局的位置(View的onLayout方法就是空方法)。
draw
等到测量和布局都完了,就可以进行真正的视图绘制了。View的绘制主要有四步:1. 绘制背景
2. 绘制自己(onDraw)
3. 绘制children(dispatchDraw)
4. 绘制装饰
每个视图的内容部分肯定都是不相同的,所以View的onDraw()是空方法,这部分的功能交给子类来去实现。
第四步的作用是对当前视图的所有子视图进行绘制。但如果当前的视图没有子视图,那么也就不需要进行绘制了。因此你会发现View中的dispatchDraw()方法又是一个空方法。
乌啦啦,View的工作流程就说完了,谢谢观看!有问题请留言,欢迎讨论~
方法论就这些,后面博主会放一个Github的demo链接,有兴趣的小伙伴可以瞅瞅。to be continued…
相关文章推荐
- android沉浸式文章集锦
- android4.4+实现MD状态栏并全屏显示内容
- android注册 登录 修改帐号密码 添加资料 给新注册用户充值DEMO
- android out目录从源代码中分离出来
- android三种传输方案分析+一个注册登录例子
- Android去掉Activity的头部标题栏
- android handler使用
- android 编译生成的out目录结构剖析
- android手机解决mimen病毒问题
- Android冷知识(3)自定义权限广播
- Android获取相册图片路径为空
- android 用户态和内核态
- android BottomNavigationBar——底部导航栏
- 高德地图infowindow点击其他地方消失
- Android Telephony分析(五) ---- TelephonyRegistry详解
- android 功耗分析主要步骤
- Android应用界面开发07
- Android bugreport文件结构解析
- Android dumpsys 命令详解
- CheckBox设置选中颜色与点击涟漪颜色