【转载】深入剖析自定义View之onMeasure
1.前言
自定义View中我们看到很多都重写了onMeasure方法,那么我们首先得知道onMeasure是做什么的。onMeasure中文意思就是测量,所以它是用于测量View的大小,影响View大小的因素很多(父View的大小、padding、自身margin、weight),View中有一个measure方法,它会对所有View调用onMeasure方法用于测量所有View的width和height。
2.代码分析
解决自定义View占用onMeasure的部分代码:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   int widthMode = MeasureSpec.getMode(widthMeasureSpec);
   int heightMode = MeasureSpec.getMode(heightMeasureSpec);
   int widthSize = MeasureSpec.getSize(widthMeasureSpec);
   int heightSize = MeasureSpec.getSize(heightMeasureSpec);  
   int width;
   int height;
   ...   
   if (widthMode == MeasureSpec.EXACTLY) {
       // Parent has told us how big to be. So be it.
       width = widthSize;
   } else {
       if (mLayout != null && mEllipsize == null) {
           des = desired(mLayout);
       }  
   ...
   setMeasuredDimension(width, height);
从系统View中onMeasure方法可以看到其中出现了MeasureSpec类、widthMeasureSpec和heightMeasureSpec变量,这些变量又是从什么地方产生的以及有什么用途,首先我们知道onMeasure是ViewGroup的onMeasure调用的,因此参数必定是父ViewGroup传入的,待稍后我们通过系统代码展示父ViewGroup如何产生这个参数。
3.MeasureSpec
widthMeasureSpec和heightMeasureSpec变量是用于描述View宽和高的模式与尺寸,对于measureSpec来说,其实隐含两个信息:size和mode,measureSpec是一个int类型值共32位,其中高2位用于存储mode,低30位用于存储size,我们可以通过MeasureSpec.getMode.和MeasureSpec.getSize方法进行分离,用于逻辑判断View具体需要的size。

我们知道在ViewGroup中,给View分配的控件大小并不是确定的,有可能随着具体的变化而变化,而这个变化的条件就是传给SpectMode中决定,specMode一共有三种情况:
  MeasureSpec.EXACTLY
    父视图希望子视图的大小应该是父控件指定的specSize值。
  MeasureSpec.AT_MOST
    子视图的大小最多是specSize中指定的值,也就是说不建议子视图的大小超过specSize中给定的值。
  MeasureSpec.UNSPECIFIED
    我们可以随意指定视图的大小。
通过以上的这些分析,可以知道视图最终的大小由父视图,子视图以及程序员根据需求决定,良好的设计一般会根据子视图的measureSpec设置合适的布局大小。
此时有一个一问,我们XML中设置的windth和height如何对应到onMeasure中的两个参数的呢?我们用源码来进行讲解:
//ViewGroup中的获取,用不传递给ChildView
childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
private static int getRootMeasureSpec(int windowSize, int rootDimension) {
    int measureSpec;
    switch (rootDimension) {  
    case ViewGroup.LayoutParams.MATCH_PARENT:
        // Window can't resize. Force root view to be windowSize.
        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
        break;
    case ViewGroup.LayoutParams.WRAP_CONTENT:
        // Window can resize. Set max size for root view.
        measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
        break;
    default:
        // Window wants to be an exact size. Force root view to be that size.
        measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
        break;
    }
    return measureSpec;
}
从代码中可以看出,MATCH_PARENT对应于EXACTLY,WRAP_CONTENT对应于AT_MOST,其他情况对应于EXACTLY,它和MATCH_PARENT的区别在于size值不一样。
根据以上提到的方法我们能够获得父ViewGroup允许的高度和宽度以及模式,再根据本身View的逻辑进行计算应有的宽度和模式,然后通过setMeasuredDimension方法将自身高度和宽度进行设置,则View的测量就完成。
自定义常用
在我们自定义View测量时,可能还会用到其他一些方法,如:
- View.resolveSize(int size, int measureSpec) 
 用于计算自身期望值和父视图提供值在模式下应该拥有的值,这个值可能等于自身期望值也可能低于期望值,因为父控件值影响
- MeasureSpec.makeMeasureSpec(int size, int mode) 
 用于当我们自定义ViewGroup的时候使用mode和size获得Spec
- view.getMeasuredWidth 
 用于获取View的宽度测量值
- view.getMeasureHeight 
 用于获取View的高度测量值
- getChildMeasureSpec 
 用于获取子控件的MeasureSpec值
作者:老柏的博客
链接:http://www.jianshu.com/p/ba2e73899cc7
【转载】深入剖析自定义View之onMeasure的更多相关文章
- 自定义View之onMeasure()
		1.自定义View之onMeasure() 2.onMeasure实例分析 
- 转    自定义View之onMeasure()
		可以说重载onMeasure(),onLayout(),onDraw()三个函数构建了自定义View的外观形象.再加上onTouchEvent()等重载视图的行为,可以构建任何我们需要的可感知到的自定 ... 
- 转载爱哥自定义View系列--Paint详解
		上图是paint中的各种set方法 这些属性大多我们都可以见名知意,很好理解,即便如此,哥还是带大家过一遍逐个剖析其用法,其中会不定穿插各种绘图类比如Canvas.Xfermode.ColorFilt ... 
- android 自定义view  android onmeasure onlayot ondraw
		韩梦飞沙 韩亚飞 313134555@qq.com yue31313 han_meng_fei_sha android onmeasure onlayot ondraw 顺序 ====== 1 ... 
- 转载:android自定义view实战(温度控制表)!
		效果图 package cn.ljuns.temperature.view; import com.example.mvp.R; import android.content.Context;impo ... 
- 转载爱哥自定义View系列--Canvas详解
		上面所罗列出来的各种drawXXX方法就是Canvas中定义好的能画什么的方法(drawPaint除外),除了各种基本型比如矩形圆形椭圆直曲线外Canvas也能直接让我们绘制各种图片以及颜色等等,但是 ... 
- Android为TV端助力 转载:android自定义view实战(温度控制表)!
		效果图 package cn.ljuns.temperature.view; import com.example.mvp.R; import android.content.Context;impo ... 
- 转载爱哥自定义View系列--文字详解
		FontMetrics FontMetrics意为字体测量,这么一说大家是不是瞬间感受到了这玩意的重要性?那这东西有什么用呢?我们通过源码追踪进去可以看到FontMetrics其实是Paint的一个内 ... 
- Android的自定义View及View的绘制流程
		目标:实现Android中的自定义View,为理清楚Android中的View绘制流程“铺路”. 想法很简单:从一个简单例子着手开始编写自定义View,对ViewGroup.View类中与绘制View ... 
随机推荐
- ESP8266 SDK开发: 开发环境搭建
			前言 这节安装下编程软件, 可以去官网下载, https://wiki.ai-thinker.com/ai_ide_install 也可以安装我提供的(我使用的为官方以前版本) 建议安装我提供的,有问 ... 
- TCP/IP协议族体系结构:死也不能忘记的四个层
			1.死也不能忘记的四个层 ①数据链路层实现了网卡接口的网络驱动程序,以处理数据在物理媒介(比如以太网.令牌环等)上的传输.主要的协议ARP和RARP经过数据链路层封装的数据成为帧,有以太网帧.令牌环帧 ... 
- curl用法详解
			前言 昨天现场的浏览器崩溃了,楼主苦逼,就临时用了curl测试了下图片请求接口.今天总结下. 一.what? curl is a tool to transfer data from or to a ... 
- 使用IDEA创建一个Servlet应用程序
			使用IDEA创建一个Servlet应用程序 第一步:创建web应用 选择web application应用,之后填写项目名称等. 第二步:项目配置 在WEB-INF目录下创建两个文件夹:classes ... 
- windows server 2008的系统备份
			添加windows server backup功能,打开运行“服务器管理器”->“功能”选项, 点击“添加功能”,选择“Windows Server Backup”,选择下一步安装该功能. 点击 ... 
- 此页面上的脚本造成Web浏览器运行速度减慢。如果继续运行,您的计算机将可能停止响应。
			访问者所使用的浏览器不能完全支持页面里的脚本,形成“脚本错误”.遇到“脚本错误”时一般会弹出一个非常难看的脚本运行错误警告窗口,而事实上,脚本错误并不会影响网站浏览,因此这一警告可谓多此一举.要关闭警 ... 
- 11. Scala数据结构(下)-集合操作
			11.1 集合元素的映射-map映射操作 11.1.1 看一个实际需求 要求:请将List(3,5,8)中所有的元素都*2,将其结果放到一个新的集合中返回,即返回一个新的List(6,10,16),请 ... 
- Linux常用命令wc
			wc名字来源: wc -- word, line, character, and byte count The wc utility displays the number of lines, wor ... 
- C# Winform 打印控件PrintDocument
			由于本着节约的原则,这里的打印都只是保存为.oxps格式的文件. 在我调试时每次打印完成后,窗体都会自己闪退. 在网上并没有相关资料,经过加入断点确认问题在 private void btnPrint ... 
- Deepo
			Deepo is a series of Docker images that allows you to quickly set up your deep learning research env ... 
