Android UI 绘制过程浅析(二)onMeasure过程
前言
View的绘制过程分为 measure、layout、draw三个步骤,接下来对这三个步骤逐一进行研究。
measure方法的签名
- public final void measure(int widthMeasureSpec, int heightMeasureSpec);
measure方法用来测量View的尺寸。两个参数widthMeasureSpec/heightMeasureSpec声明了Parent View所能提供的宽/高。
需要注意的是,widthMeasureSpec/heightMeasureSpec 这两个 int 型的参数是复合参数(compound parameters)。jvm中以32bit来存储int,最高两位表示“mode”,后面30位才是具体的数值。在View.java中有下面两个方法
- /**
- * Extracts the mode from the supplied measure specification.
- *
- * @param measureSpec the measure specification to extract the mode from
- * @return {@link android.view.View.MeasureSpec#UNSPECIFIED},
- * {@link android.view.View.MeasureSpec#AT_MOST} or
- * {@link android.view.View.MeasureSpec#EXACTLY}
- */
- public static int getMode(int measureSpec) {
- return (measureSpec & MODE_MASK);
- }
- /**
- * Extracts the size from the supplied measure specification.
- *
- * @param measureSpec the measure specification to extract the size from
- * @return the size in pixels defined in the supplied measure specification
- */
- public static int getSize(int measureSpec) {
- return (measureSpec & ~MODE_MASK);
- }
看到了吧,使用位操作&来获取最高两位的mode。2^2=4,这里只有用到了3种,它们分别的含义入下
- UNSPECIFIED-ParentView对子View没有约束,后者可以是任意大小
- AT_MOST-ParentView规定了尺寸上限,子View的大小不可以超过这个上限
- EXACTLY-ParentView规定了子View的宽高,子View只能是这个宽高
measure方法本身是声明为final的,CustomView必须实现自己的onMeasure方法,以便View.measure对此进行回调。在实现自己的CustomView.onMeasure之前,先来看看View中默认的onMeasure方法。
onMeasure
在自定义View中,往往需要重写onMeasure方法,来设置View的measured width/height。要注意的一点是,计算完成后,必须调用setMeasuredDimension(int, int)来设置宽高,不然在上层measure方法会抛出IllegalStateException。自定View计算出的宽/高必须满足最小宽/高(通过getSuggestedMinimumWidth()、getSuggestedMinimumHeight()获取)。当然也可以在自定义View的onMeasure方法中直接调用View.onMeasure,如下
- @Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- }
然而,View默认的onMeasure实现逻辑非常简单,恐怕不能满足自定义View的需求。
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
- getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
- }
View.onMeasure简单粗暴地调用了setMeasuredDimension来设置measuredWidth/measuredHeight。其中使用的getDefaultSize(int, int)方法如下
- 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;
- }
逻辑很简单,一个switch/case语句,根据SpecMode来判断返回。若为UNSPECIFIED,则返回minimumWidth;若为AT_MOST/EXACTLY,返回SpecWidth。
到此为止,View的measure过程已经完成了。对于ViewGroup,可以猜想,它的onMeasure方法,是把所有子View的onMeasure做一次相加。我们来看一下具体是不是这样做的。
ViewGroup.measure
ViewGroup继承了View类,理所应当地,我们试图在ViewGroup中查找是否重写了onMeasure方法——未果。不过我们惊喜地发现了measureChildren这个方法——用来遍历所有children,对每一个child进行measure
- 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);
- }
- }
- }
measureChild中,将ViewGroup的padding加入了计算,最后调用child.measure,这里不予深究,也不再贴出代码。
ViewGroup.java本身并没有重写onMeasure方法,在它的具体实现中,onMeasure根据具体情况,将children的measured size进行求和处理,具体可以参阅FrameLayout/LiearLayout/RelativeLayout 的代码。
小结
对于measure过程的分析就到这里,下一篇我们继续探讨onLayout过程。
Android UI 绘制过程浅析(二)onMeasure过程的更多相关文章
- Android UI 绘制过程浅析(五)自定义View
前言 这已经是Android UI 绘制过程浅析系列文章的第五篇了,不出意外的话也是最后一篇.再次声明一下,这一系列文章,是我在拜读了csdn大牛郭霖的博客文章<带你一步步深入了解View> ...
- 传感器仿真平台——UI绘制模块(二)
这一章讲的是UI绘制模块 该模块的作用是将实验对象绘制出来,它可能是目标.传感器等等,由于事先并不知道会有哪些物体,也无法事先定义好某个对象该怎么画,以我懒人的性格,得了,就抛给用的人吧~喝前摇一摇, ...
- Android UI 绘制过程浅析(四)draw过程
前言 draw是绘制View三个步骤中的最后一步.同measure.layout一样,通常不对draw本身进行重写,draw内部会调用onDraw方法,子类View需要重写onDraw(Canvas) ...
- Android UI 绘制过程浅析(三)layout过程
前言 上一篇blog中,了解到measure过程对View进行了测量,得到measuredWidth/measuredHeight.对于ViewGroup,则计算出全部children的宽高进行求和. ...
- Android UI 绘制过程浅析(一)LayoutInflater简介
前言 这篇blog是我在阅读过csdn大牛郭霖的<带你一步步深入了解View>一系列文章后,亲身实践并做出的小结.作为有志向的前端开发工程师,怎么可以不搞懂View绘制的基本原理——简直就 ...
- Android UI绘制流程及原理
一.绘制流程源码路径 1.Activity加载ViewRootImpl ActivityThread.handleResumeActivity() --> WindowManagerImpl.a ...
- 简单研究Android View绘制一 测量过程
2015-07-27 16:52:58 一.如何通过继承ViewGroup来实现自定义View?首先得搞清楚Android时如何绘制View的,参考Android官方文档:How Android Dr ...
- Android UI开发第四十一篇——墨迹天气3.0引导界面及动画实现
周末升级了墨迹天气,看着引导界面做的不错,模仿一下,可能与原作者的代码实现不一样,但是实现的效果还是差不多的.先分享一篇以前的文章,android动画的基础知识,<Android UI开发第十二 ...
- 简单研究Android View绘制三 布局过程
2015-07-28 17:29:19 这一篇主要看看布局过程 一.布局过程肯定要不可避免的涉及到layout()和onLayout()方法,这两个方法都是定义在View.java中,源码如下: /* ...
随机推荐
- 【matlab】MATLAB程序调试方法和过程
3.8 MATLAB程序的调试和优化 在MATLAB的程序调试过程中,不仅要求程序能够满足设计者的设计需求,而且还要求程序调试能够优化程序的性能,这样使得程序调试有时比程序设计更为复杂.MATLAB ...
- Oracle GoldenGate for Big Data 12.2.0.1的新特性
ogg for bigdata 12.2已经发布,新增有如下特性:支持java replicat进程OGG12.2中开发了基于java的replicat模式,以前的版本是基于extract进程中使用u ...
- 12-8下午 php语法
<?php //var_dump(empty($a)); //判断变量是否为空//var_dump(isset($a)); //判断变量是否定义//$a = 10;//unset($a); // ...
- Neuroaesthetics神经美学
欢迎您到脑科学的世界! 神经美学(或neuroaesthetics)是一个相对较新的经验主义美学的子学科.经验主义美学需要科学的方法来研究艺术和音乐的审美观念. neuroesthetics于2002 ...
- 问:Linux下Chrome标题栏中文乱码
From:http://blog.csdn.net/loveaborn/article/details/29579787 在使用Linux的时候你会遇到一些奇奇怪怪的问题,不过,你会在解决这些问题的过 ...
- excel导入导出
using System; using System.Collections.Generic; using System.Linq; using System.Text; using FS.Exten ...
- Jqgrid 数据格式化配置
默认格式化 $jgrid = { formatter : { integer : {thousandsSeparator: " ", defaultValue: '0'}, num ...
- SPOJ QTREE Query on a tree
题意:给一颗n个点的树,有两种操作CHANGE i ti : 把第i条边的权变为tiQUERY a b : 问点a 到 点b 之间的边的最大权 思路:树剖处理边权.由于是边,所以只需要把边权处理到子节 ...
- (转)注意力机制(Attention Mechanism)在自然语言处理中的应用
注意力机制(Attention Mechanism)在自然语言处理中的应用 本文转自:http://www.cnblogs.com/robert-dlut/p/5952032.html 近年来,深度 ...
- 由javascript中的this指针所想到的
初次结识 this 指针,是在学 <<C++ Primer Plus>>这本书的时候(这本书勉强读了一二遍,之后转学 html+css+js了,不过这是后话). 依稀记得书中举 ...