自定义view 重写onMeasure()方法
来源:互联网 发布:年金保险 知乎 编辑:程序博客网 时间:2024/06/05 00:26
<div id="article_details" class="details">
<div class="article_title">
<span class="ico ico_type_Repost"></span>
<h1>
<span class="link_title"><a href="/easyer2012/article/details/37900583">
ANDROID自定义视图——onMeasure流程,MeasureSpec详解
</a></span>
</h1>
</div>
<div class="article_manage">
<span class="link_categories">
分类:
<a href="/easyer2012/article/category/1167761" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">android 高手进阶教程</a>
</span>
<span class="link_postdate">2014-07-17 09:09</span>
<span class="link_view" title="阅读次数">83人阅读</span>
<span class="link_comments" title="评论次数"><a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(0)</span>
<span class="link_collect"><a href="javascript:void(0);" onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shoucang']);collectArticle('ANDROID自定义视图——onMeasure流程,MeasureSpec详解','37900583');return false;" title="收藏">收藏</a></span>
<span class="link_report"><a href="#report" onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_jubao']);report(37900583,2);return false;" title="举报">举报</a></span>
</div>
<div id="article_content" class="article_content">
<p><span style="font-size:24px; color:#cc0000"><strong>简介:</strong></span></p>
<p><span style="font-size:18px">在自定义view的时候,其实很简单,只需要知道3步骤:</span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">1.测量——onMeasure():决定View的大小</span></span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">2.布局——onLayout():决定View在ViewGroup中的位置</span></span></p>
<p><span style="font-size:18px"><span style="font-family:Arial; color:#333333; line-height:26px">3.绘制——onDraw():如何绘制这个View。</span><br>
</span></p>
<p><span style="font-size:18px">而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到<span style="font-family:Arial; font-size:18px; color:#333333; line-height:26px">1</span>,2两个步骤就中好了。</span></p>
<p><span style="font-size:18px">而这篇文章就来谈谈第一步,也是十分关键得一步:“<strong>测量(Measure)</strong>”</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">Measure():</span></strong></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">Measure的中文意思就是测量。所以它的作用就是测量View的大小。</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">而决定View的大小只需要两个值:宽<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">详细</span>测量值(widthMeasureSpec)和高<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">详细</span>测量值(heightMeasureSpec)。也可以把详细测量值理解为视图View想要的大小说明(想要的未必就是最终大小)。</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">对于详细测量值(<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">measureSpec</span>)需要两样东西来确定它,那就是大小(size)和模式(mode)。</span></span><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">而</span><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">measureSpec,size,mode他们三个的关系,都封装在View类中的一个内部类里,名叫<strong>MeasureSpec</strong>。</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><br>
</span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">MeasureSpec:</span></strong></span><br>
</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">因为MeasureSpec类很小,而且设计的很巧妙,所以我贴出了全部的源码并进行了详细的标注。(<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">掌握MeasureSpec的机制后会对整个Measure方法有更深刻的理解。)</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></span></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 1170px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求</span> </span></li><li class="alt"><span><span class="comment"> * MeasureSpec由size和mode组成。</span> </span></li><li><span><span class="comment"> * 三种Mode:</span> </span></li><li class="alt"><span><span class="comment"> * 1.UNSPECIFIED</span> </span></li><li><span><span class="comment"> * 父不没有对子施加任何约束,子可以是任意大小(也就是未指定)</span> </span></li><li class="alt"><span><span class="comment"> * (UNSPECIFIED在源码中的处理和EXACTLY一样。当View的宽高值设置为0的时候或者没有设置宽高时,模式为UNSPECIFIED</span> </span></li><li><span><span class="comment"> * 2.EXACTLY</span> </span></li><li class="alt"><span><span class="comment"> * 父决定子的确切大小,子被限定在给定的边界里,忽略本身想要的大小。</span> </span></li><li><span><span class="comment"> * (当设置width或height为match_parent时,模式为EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)</span> </span></li><li class="alt"><span><span class="comment"> * 3.AT_MOST</span> </span></li><li><span><span class="comment"> * 子最大可以达到的指定大小</span> </span></li><li class="alt"><span><span class="comment"> * (当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)</span> </span></li><li><span><span class="comment"> * </span> </span></li><li class="alt"><span><span class="comment"> * MeasureSpecs使用了二进制去减少对象的分配。</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> MeasureSpec { </span></span></li><li><span> <span class="comment">// 进位大小为2的30次方(int的大小为32位,所以进位30位就是要使用int的最高位和倒数第二位也就是32和31位做标志位)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> MODE_SHIFT = </span><span class="number">30</span><span>; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 运算遮罩,0x3为16进制,10进制为3,二进制为11。3向左进位30,就是11 00000000000(11后跟30个0)</span><span> </span></span></li><li><span> <span class="comment">// (遮罩的作用是用1标注需要的值,0标注不要的值。因为1与任何数做与运算都得任何数,0与任何数做与运算都得0)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> MODE_MASK = </span><span class="number">0x3</span><span> << MODE_SHIFT; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 0向左进位30,就是00 00000000000(00后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> UNSPECIFIED = </span><span class="number">0</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> <span class="comment">// 1向左进位30,就是01 00000000000(01后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> EXACTLY = </span><span class="number">1</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> <span class="comment">// 2向左进位30,就是10 00000000000(10后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> AT_MOST = </span><span class="number">2</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 根据提供的size和mode得到一个详细的测量结果</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// measureSpec = size + mode; (注意:二进制的加法,不是10进制的加法!)</span><span> </span></span></li><li><span> <span class="comment">// 这里设计的目的就是使用一个32位的二进制数,32和31位代表了mode的值,后30位代表size的值</span><span> </span></span></li><li class="alt"><span> <span class="comment">// 例如size=100(4),mode=AT_MOST,则measureSpec=100+10000...00=10000..00100</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> makeMeasureSpec(</span><span class="keyword">int</span><span> size, </span><span class="keyword">int</span><span> mode) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> size + mode; </span></span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 通过详细测量结果获得mode</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// mode = measureSpec & MODE_MASK;</span><span> </span></span></li><li><span> <span class="comment">// MODE_MASK = 11 00000000000(11后跟30个0),原理是用MODE_MASK后30位的0替换掉measureSpec后30位中的1,再保留32和31位的mode值。</span><span> </span></span></li><li class="alt"><span> <span class="comment">// 例如10 00..00100 & 11 00..00(11后跟30个0) = 10 00..00(AT_MOST),这样就得到了mode的值</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getMode(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> (measureSpec & MODE_MASK); </span></span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 通过详细测量结果获得size</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// size = measureSpec & ~MODE_MASK;</span><span> </span></span></li><li><span> <span class="comment">// 原理同上,不过这次是将MODE_MASK取反,也就是变成了00 111111(00后跟30个1),将32,31替换成0也就是去掉mode,保留后30位的size</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getSize(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li><span> <span class="keyword">return</span><span> (measureSpec & ~MODE_MASK); </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">/**</span> </span></li><li><span><span class="comment"> * 重写的toString方法,打印mode和size的信息,这里省略</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> String toString(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">null</span><span>; </span></span></li><li><span> } </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong><br>
</strong></span></span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong>源码中的onMeasure()</strong></span><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong>:</strong></span><br>
</span></p>
<p><span style="font-size:18px"><span style="font-family:Arial; color:#333333; line-height:26px">知道了widthMeasureSpec和heightMeasureSpec是什么以后</span><span style="font-family:Arial; color:#333333; line-height:26px">,我们就可以来看onMeasure方法了:</span></span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 2691px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 这个方法需要被重写,应该由子类去决定测量的宽高值,</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), </span></li><li><span> getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-size:18px">在onMeasure中只调用了setMeasuredDimension()方法,接受两个参数,这两个参数是通过<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize方法得到的,我们到源码里看看<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize究竟做了什么</span></span>。</span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">getDefaultSize():</span></strong></span><br>
</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 2976px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 作用是返回一个默认的值,如果MeasureSpec没有强制限制的话则使用提供的大小.否则在允许范围内可任意指定大小</span> </span></li><li class="alt"><span><span class="comment"> * 第一个参数size为提供的默认大小,第二个参数为测量的大小</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getDefaultSize(</span><span class="keyword">int</span><span> size, </span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li><span> <span class="keyword">int</span><span> result = size; </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> specMode = MeasureSpec.getMode(measureSpec); </span></span></li><li><span> <span class="keyword">int</span><span> specSize = MeasureSpec.getSize(measureSpec); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="keyword">switch</span><span> (specMode) { </span></span></li><li class="alt"><span> <span class="comment">// Mode = UNSPECIFIED,AT_MOST时使用提供的默认大小</span><span> </span></span></li><li><span> <span class="keyword">case</span><span> MeasureSpec.UNSPECIFIED: </span></span></li><li class="alt"><span> result = size; </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.AT_MOST: </span></span></li><li><span> <span class="comment">// Mode = EXACTLY时使用测量的大小 </span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.EXACTLY: </span></span></li><li><span> result = specSize; </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> result; </span></span></li><li><span> } </span></li></ol>
</div>
<span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-size:18px">getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),这里就是获取最小宽度作为默认值,然后再根据具体的测量值和选用的模式来得到<span style="color:rgb(51,51,51); font-family:Arial; line-height:26px">widthMeasureSpec。<span style="font-family:Arial; color:#333333; line-height:26px">heightMeasureSpec同理。之后将<span style="font-family:Arial; color:#333333; line-height:26px">widthMeasureSpec,</span><span style="font-family:Arial; color:#333333; line-height:26px">heightMeasureSpec传入<span style="font-family:Arial; color:#333333; line-height:26px">setMeasuredDimension()方法。</span></span></span></span></span></span>
<p><span style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><span style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><br>
</span></span></span></span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-size:24px; color:#cc0000"><strong>setMeasuredDimension():</strong></span></span></span></span></span></span></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 3634px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 这个方法必须由onMeasure(int, int)来调用,来存储测量的宽,高值。</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">void</span><span> setMeasuredDimension(</span><span class="keyword">int</span><span> measuredWidth, </span><span class="keyword">int</span><span> measuredHeight) { </span></span></li><li class="alt"><span> mMeasuredWidth = measuredWidth; </span></li><li><span> mMeasuredHeight = measuredHeight; </span></li><li class="alt"><span> </span></li><li><span> mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; </span></li><li class="alt"><span>} </span></li></ol>
</div>
<span style="font-size:18px">这个方法就是我们重写onMeasure()所要实现的最终目的。它的作用就是存储我们测量好的宽高值。</span>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">这下思路清晰了,现在的任务就是<span style="font-family:Arial; color:#333333; line-height:26px">计算出准确</span>的measuredWidth和heightMeasureSpec并传递进去,我们所有<span style="font-family:Arial; color:#333333; line-height:26px">的测量任务就算完成了。</span></span></span></p>
<p><span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">源码中使用的<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize()只是简单的测量了宽高值,在实际使用时需要精细、具体的测量。而</span>具体的测量任务就交给我们在子类中重写的onMeasure方法。</span></span></span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px"><br>
</span></span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-size:24px; color:#cc00"><strong>在子类中重写的onMeasure:</strong></span></span></p>
<p><span style="font-size:18px">在测量之前首先要明确一点,需要测量的是一个View(例如TextView),还是一个ViewGroup(例如LinearLayout),还是多个ViewGroup嵌套。如果只有一个View的话我们就测量这一个就可以了,如果有多个View或者ViewGroup嵌套我们就需要循环遍历视图中所有的View。</span></p>
<p><span style="font-size:18px">下面列出一个最简单的小例子,写一个自定义类CostomViewGroup继承自ViewGroup,然后重写它的构造方法,onMeasure和onLayout方法。用这个自定义的ViewGroup去写一个布局文件如下:</span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 4331px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_5" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=5&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span><com.gxy.text.CostomViewGroup xmlns:android=</span><span class="string">"http://schemas.android.com/apk/res/android"</span><span> </span></span></li><li><span> android:layout_width=<span class="string">"match_parent"</span><span> </span></span></li><li class="alt"><span> android:layout_height=<span class="string">"match_parent"</span><span> </span></span></li><li><span> android:background=<span class="string">"#bbbaaa"</span><span> </span></span></li><li class="alt"><span> > </span></li><li><span> <Button </span></li><li class="alt"><span> android:text=<span class="string">"@string/hello_world"</span><span> </span></span></li><li><span> android:layout_width=<span class="string">"match_parent"</span><span> </span></span></li><li class="alt"><span> android:layout_height=<span class="string">"wrap_content"</span><span> </span></span></li><li><span> android:background=<span class="string">"#aaabbb"</span><span> </span></span></li><li class="alt"><span> android:id=<span class="string">"@+id/textView1"</span><span> /> </span></span></li><li><span></com.gxy.text.CostomViewGroup> </span></li></ol>
</div>
<span style="font-size:18px">将一个Button放入自定义的ViewGroup中,然后在MainActivity的onCreate回调方法中调用setContentView把整个布局文件设置进去。</span>
<p><span style="font-size:18px">最后看一下自定义CostomViewGroup中的onMeasure方法的内容:</span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 4704px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_6" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=6&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="annotation">@Override</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//调用ViewGroup类中测量子类的方法</span><span> </span></span></li><li class="alt"><span> measureChildren(widthMeasureSpec, heightMeasureSpec); </span></li><li><span> <span class="comment">//调用View类中默认的测量方法</span><span> </span></span></li><li class="alt"><span> <span class="keyword">super</span><span>.onMeasure(widthMeasureSpec,heightMeasureSpec); </span></span></li><li><span> </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-size:18px">本文只是介绍测量,所以onLayout方法先省略,下面来看看效果图:</span></p>
<p><img src="http://img.blog.csdn.net/20140716223856156?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<span style="font-size:18px">在子类重写的onMeasure中只调用两个方法,第一个是父类的onMeasure方法,之前已经介绍了它的作用,它最后会调用<span style="font-family:Arial; color:#333333; line-height:26px">setMeasuredDimension()将测量好的宽高值传递进去。第二个会调用measureChildren方法,它的作用是测量所有的子View,下面我们看看它是如何工作的。</span></span>
<p><span style="font-size:24px; color:#cc00"><strong>measureChildren()</strong></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 5705px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_7" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_7" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=7&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span> </span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 遍历所有的子view去测量自己(跳过GONE类型View)</span> </span></li><li class="alt"><span><span class="comment"> * @param widthMeasureSpec 父视图的宽详细测量值</span> </span></li><li><span><span class="comment"> * @param heightMeasureSpec 父视图的高详细测量值</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> measureChildren(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> size = mChildrenCount; </span></span></li><li><span> <span class="keyword">final</span><span> View[] children = mChildren; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < size; ++i) { </span></span></li><li><span> <span class="keyword">final</span><span> View child = children[i]; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> ((child.mViewFlags & VISIBILITY_MASK) != GONE) { </span></span></li><li><span> measureChild(child, widthMeasureSpec, heightMeasureSpec); </span></li><li class="alt"><span> } </span></li><li><span> } </span></li><li class="alt"><span>} </span></li></ol>
</div>
<span style="font-size:18px">代码很简单,就是遍历所有的子View,如果View的状态不是GONE就调用measureChild去进行下一步的测量</span>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>measureChild()</strong></span><br>
</p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 6170px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_8" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_8" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=8&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 测量单个视图,将宽高和padding加在一起后交给getChildMeasureSpec去获得最终的测量值</span> </span></li><li class="alt"><span><span class="comment"> * @param child 需要测量的子视图</span> </span></li><li><span><span class="comment"> * @param parentWidthMeasureSpec 父视图的宽详细测量值</span> </span></li><li class="alt"><span><span class="comment"> * @param parentHeightMeasureSpec 父视图的高详细测量值</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> measureChild(View child, </span><span class="keyword">int</span><span> parentWidthMeasureSpec, </span></span></li><li><span> <span class="keyword">int</span><span> parentHeightMeasureSpec) { </span></span></li><li class="alt"><span> <span class="comment">// 取得子视图的布局参数</span><span> </span></span></li><li><span> <span class="keyword">final</span><span> LayoutParams lp = child.getLayoutParams(); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 通过getChildMeasureSpec获取最终的宽高详细测量值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, </span></span></li><li><span> mPaddingLeft + mPaddingRight, lp.width); </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, </span></span></li><li><span> mPaddingTop + mPaddingBottom, lp.height); </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 将计算好的宽高详细测量值传入measure方法,完成最后的测量</span><span> </span></span></li><li class="alt"><span> child.measure(childWidthMeasureSpec, childHeightMeasureSpec); </span></li><li><span>} </span></li></ol>
</div>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>getChildMeasureSpec()</strong></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 6658px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_9" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_9" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=9&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 在measureChildren中最难的部分:找出传递给child的MeasureSpec。</span> </span></li><li class="alt"><span><span class="comment"> * 目的是结合父view的MeasureSpec与子view的LayoutParams信息去找到最好的结果</span> </span></li><li><span><span class="comment"> * (也就是说子view的确切大小由两方面共同决定:1.父view的MeasureSpec 2.子view的LayoutParams属性)</span> </span></li><li class="alt"><span><span class="comment"> * </span> </span></li><li><span><span class="comment"> * @param spec 父view的详细测量值(MeasureSpec)</span> </span></li><li class="alt"><span><span class="comment"> * @param padding view当前尺寸的的内边距和外边距(padding,margin)</span> </span></li><li><span><span class="comment"> * @param childDimension child在当前尺寸下的布局参数宽高值(LayoutParam.width,height)</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getChildMeasureSpec(</span><span class="keyword">int</span><span> spec, </span><span class="keyword">int</span><span> padding, </span><span class="keyword">int</span><span> childDimension) { </span></span></li><li class="alt"><span> <span class="comment">//父view的模式和大小</span><span> </span></span></li><li><span> <span class="keyword">int</span><span> specMode = MeasureSpec.getMode(spec); </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> specSize = MeasureSpec.getSize(spec); </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">//通过父view计算出的子view = 父大小-边距(父要求的大小,但子view不一定用这个值) </span><span> </span></span></li><li><span> <span class="keyword">int</span><span> size = Math.max(</span><span class="number">0</span><span>, specSize - padding); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//子view想要的实际大小和模式(需要计算)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> resultSize = </span><span class="number">0</span><span>; </span></span></li><li><span> <span class="keyword">int</span><span> resultMode = </span><span class="number">0</span><span>; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//通过1.父view的MeasureSpec 2.子view的LayoutParams属性这两点来确定子view的大小</span><span> </span></span></li><li class="alt"><span> <span class="keyword">switch</span><span> (specMode) { </span></span></li><li><span> <span class="comment">// 当父view的模式为EXACITY时,父view强加给子view确切的值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.EXACTLY: </span></span></li><li><span> <span class="comment">// 当子view的LayoutParams>0也就是有确切的值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> <span class="comment">//子view大小为子自身所赋的值,模式大小为EXACTLY</span><span> </span></span></li><li class="alt"><span> resultSize = childDimension; </span></li><li><span> resultMode = MeasureSpec.EXACTLY; </span></li><li class="alt"><span> <span class="comment">// 当子view的LayoutParams为MATCH_PARENT时(-1)</span><span> </span></span></li><li><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li class="alt"><span> <span class="comment">//子view大小为父view大小,模式为EXACTLY</span><span> </span></span></li><li><span> resultSize = size; </span></li><li class="alt"><span> resultMode = MeasureSpec.EXACTLY; </span></li><li><span> <span class="comment">// 当子view的LayoutParams为WRAP_CONTENT时(-2) </span><span> </span></span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> <span class="comment">//子view决定自己的大小,但最大不能超过父view,模式为AT_MOST</span><span> </span></span></li><li class="alt"><span> resultSize = size; </span></li><li><span> resultMode = MeasureSpec.AT_MOST; </span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。</span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.AT_MOST: </span></span></li><li><span> <span class="comment">// 道理同上</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> resultSize = childDimension; </span></li><li class="alt"><span> resultMode = MeasureSpec.EXACTLY; </span></li><li><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li class="alt"><span> resultSize = size; </span></li><li><span> resultMode = MeasureSpec.AT_MOST; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> resultSize = size; </span></li><li class="alt"><span> resultMode = MeasureSpec.AT_MOST; </span></li><li><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 当父view的模式为UNSPECIFIED时,子view为想要的值</span><span> </span></span></li><li><span> <span class="keyword">case</span><span> MeasureSpec.UNSPECIFIED: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> <span class="comment">// 子view大小为子自身所赋的值</span><span> </span></span></li><li class="alt"><span> resultSize = childDimension; </span></li><li><span> resultMode = MeasureSpec.EXACTLY; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li><span> <span class="comment">// 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0</span><span> </span></span></li><li class="alt"><span> resultSize = <span class="number">0</span><span>; </span></span></li><li><span> resultMode = MeasureSpec.UNSPECIFIED; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> <span class="comment">// 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0</span><span> </span></span></li><li class="alt"><span> resultSize = <span class="number">0</span><span>; </span></span></li><li><span> resultMode = MeasureSpec.UNSPECIFIED; </span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">return</span><span> MeasureSpec.makeMeasureSpec(resultSize, resultMode); </span></span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-size:18px">可能看完后感觉有点迷糊,接下来通过几个例子演示一下,可能大家就会对getChildMeasureSpec方法中的逻辑清晰一些。</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px">1.当父类View中宽高都为MATCH_PARENT(EXACTLY)时,宽高都为MATCH_PARENT(EXACTLY)时:</span></p>
<p><span style="font-size:18px">2.当父类View中宽高都为MATCH_PARENT(EXACTLY)时,宽高都为WRAP_CONTENT(EXACTLY)时:<br>
</span></p>
<p><span style="font-size:18px">3.当父类View中宽高都为MATCH_PARENT(EXACTLY)时。子类宽WRAP_CONTENT(AT_MOST),高为MATCH_PARENT(EXACTLY)时:</span><br>
</p>
<p><img src="http://img.blog.csdn.net/20140716232208687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><img src="http://img.blog.csdn.net/20140716233105536?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><img src="http://img.blog.csdn.net/20140716232846593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px">1.当父类View中宽高都为WRAP_CONTENT(AT_MOST)时,子类宽高都为MATCH_PARENT(EXACTLY)时:</span></p>
<p><span style="font-size:18px">2.当父类View中宽高都为WRAP_CONTENT(AT_MOST)时。子类宽WRAP_CONTENT(AT_MOST),高为MATCH_PARENT(EXACTLY)时:</span></p>
<p><img src="http://img.blog.csdn.net/20140716233403002?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""> <img src="http://img.blog.csdn.net/20140717002350329?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></p>
<p><span style="font-size:18px">通过这两组简单的对比,其实大家就可以把测量子类大小的代码理解为:</span></p>
<p><span style="font-size:18px">父类中MATCH_PARENT,WRAP_CONTENT,指定值和子类中的MATCH_PARENT,WRAP_CONTENT,指定值这两对值的相互作用。</span></p>
<p><span style="font-size:18px">更复杂的情况则需要加上padding内边距和margin外边距等等一些其他对于View大小的约束。</span></p>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>总结:</strong></span></p>
<p><span style="font-size:18px">今天介绍的都是系统提供的测量方法,除了这些以外还有一些其他的,大家可以看看源码。而且在真正的自定义View视图时,很大一部分都是借助这些系统提供的现成方法,并且根据需求再加上自己的特殊逻辑(当然也可以全部用自己的逻辑,但我们不要重复制造轮子)。</span></p>
<p><span style="font-size:18px">这篇文章写了2个礼拜,写之前思路非常清晰,但是在写的时候越写越乱。写完以后感觉逻辑仍然不是很清晰,因为有的内容我也是一知半解比如UNSPECIFIED。如果大家水平和我差不多都是菜鸟级别的,希望大家不要深入的去研究源码逻辑,这样会导致越来越来混乱,从应用的角度出发可能会更好一些。</span></p>
<p><span style="font-size:18px">下面会接着写onLayout和LayoutParams的相关内容。最后再将onMeasure,onLayout结合起来写一个完整的例子。也许这些都写完以后会对整个流程的思路会更加清晰。</span></p>
<p><span style="font-size:18px">来源:http://blog.csdn.net/a396901990/article/details/36475213</span></p>
<p><span style="font-size:18px"><br>
</span></p>
</div>
<!-- Baidu Button BEGIN -->
<div class="bdsharebuttonbox bdshare-button-style0-16" style="float: right;" data-bd-bind="1411716159256">
<a href="#" class="bds_more" data-cmd="more" style="background-position:0 0 !important; background-image: url(http://bdimg.share.baidu.com/static/api/img/share/icons_0_16.png?v=d754dcc0.png) !important"></a>
<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间" style="background-position:0 -52px !important"></a>
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博" style="background-position:0 -104px !important"></a>
<a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博" style="background-position:0 -260px !important"></a>
<a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网" style="background-position:0 -208px !important"></a>
<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信" style="background-position:0 -1612px !important"></a>
</div>
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "1", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script>
<!-- Baidu Button END -->
<!--192.168.100.35-->
<ul class="article_next_prev">
<li class="prev_article"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shangyipian']);location.href='/easyer2012/article/details/37872457';">上一篇</span><a href="/easyer2012/article/details/37872457" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shangyipian'])">Android UI开发第二十四篇——Action Bar</a></li>
<li class="next_article"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_xiayipian']);location.href='/easyer2012/article/details/38346695';">下一篇</span><a href="/easyer2012/article/details/38346695" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_xiayipian'])">log4j使用简介</a></li>
</ul>
<!-- Baidu Button BEGIN -->
<script type="text/javascript" id="bdshare_js" data="type=tools&uid=1536434" src="http://bdimg.share.baidu.com/static/js/bds_s_v2.js?cdnversion=392144"></script>
<script type="text/javascript">
document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)
</script>
<!-- Baidu Button END -->
</div>
<div class="article_title">
<span class="ico ico_type_Repost"></span>
<h1>
<span class="link_title"><a href="/easyer2012/article/details/37900583">
ANDROID自定义视图——onMeasure流程,MeasureSpec详解
</a></span>
</h1>
</div>
<div class="article_manage">
<span class="link_categories">
分类:
<a href="/easyer2012/article/category/1167761" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_fenlei']);">android 高手进阶教程</a>
</span>
<span class="link_postdate">2014-07-17 09:09</span>
<span class="link_view" title="阅读次数">83人阅读</span>
<span class="link_comments" title="评论次数"><a href="#comments" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_pinglun'])">评论</a>(0)</span>
<span class="link_collect"><a href="javascript:void(0);" onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shoucang']);collectArticle('ANDROID自定义视图——onMeasure流程,MeasureSpec详解','37900583');return false;" title="收藏">收藏</a></span>
<span class="link_report"><a href="#report" onclick="javascript:_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_jubao']);report(37900583,2);return false;" title="举报">举报</a></span>
</div>
<div id="article_content" class="article_content">
<p><span style="font-size:24px; color:#cc0000"><strong>简介:</strong></span></p>
<p><span style="font-size:18px">在自定义view的时候,其实很简单,只需要知道3步骤:</span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">1.测量——onMeasure():决定View的大小</span></span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">2.布局——onLayout():决定View在ViewGroup中的位置</span></span></p>
<p><span style="font-size:18px"><span style="font-family:Arial; color:#333333; line-height:26px">3.绘制——onDraw():如何绘制这个View。</span><br>
</span></p>
<p><span style="font-size:18px">而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到<span style="font-family:Arial; font-size:18px; color:#333333; line-height:26px">1</span>,2两个步骤就中好了。</span></p>
<p><span style="font-size:18px">而这篇文章就来谈谈第一步,也是十分关键得一步:“<strong>测量(Measure)</strong>”</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">Measure():</span></strong></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">Measure的中文意思就是测量。所以它的作用就是测量View的大小。</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">而决定View的大小只需要两个值:宽<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">详细</span>测量值(widthMeasureSpec)和高<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">详细</span>测量值(heightMeasureSpec)。也可以把详细测量值理解为视图View想要的大小说明(想要的未必就是最终大小)。</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px">对于详细测量值(<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">measureSpec</span>)需要两样东西来确定它,那就是大小(size)和模式(mode)。</span></span><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">而</span><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">measureSpec,size,mode他们三个的关系,都封装在View类中的一个内部类里,名叫<strong>MeasureSpec</strong>。</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><br>
</span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">MeasureSpec:</span></strong></span><br>
</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">因为MeasureSpec类很小,而且设计的很巧妙,所以我贴出了全部的源码并进行了详细的标注。(<span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px">掌握MeasureSpec的机制后会对整个Measure方法有更深刻的理解。)</span></span></p>
<p><span style="font-family:Arial; color:#333333"><span style="font-size:14px; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></span></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 1170px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_1" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=1&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求</span> </span></li><li class="alt"><span><span class="comment"> * MeasureSpec由size和mode组成。</span> </span></li><li><span><span class="comment"> * 三种Mode:</span> </span></li><li class="alt"><span><span class="comment"> * 1.UNSPECIFIED</span> </span></li><li><span><span class="comment"> * 父不没有对子施加任何约束,子可以是任意大小(也就是未指定)</span> </span></li><li class="alt"><span><span class="comment"> * (UNSPECIFIED在源码中的处理和EXACTLY一样。当View的宽高值设置为0的时候或者没有设置宽高时,模式为UNSPECIFIED</span> </span></li><li><span><span class="comment"> * 2.EXACTLY</span> </span></li><li class="alt"><span><span class="comment"> * 父决定子的确切大小,子被限定在给定的边界里,忽略本身想要的大小。</span> </span></li><li><span><span class="comment"> * (当设置width或height为match_parent时,模式为EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)</span> </span></li><li class="alt"><span><span class="comment"> * 3.AT_MOST</span> </span></li><li><span><span class="comment"> * 子最大可以达到的指定大小</span> </span></li><li class="alt"><span><span class="comment"> * (当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)</span> </span></li><li><span><span class="comment"> * </span> </span></li><li class="alt"><span><span class="comment"> * MeasureSpecs使用了二进制去减少对象的分配。</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> MeasureSpec { </span></span></li><li><span> <span class="comment">// 进位大小为2的30次方(int的大小为32位,所以进位30位就是要使用int的最高位和倒数第二位也就是32和31位做标志位)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> MODE_SHIFT = </span><span class="number">30</span><span>; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 运算遮罩,0x3为16进制,10进制为3,二进制为11。3向左进位30,就是11 00000000000(11后跟30个0)</span><span> </span></span></li><li><span> <span class="comment">// (遮罩的作用是用1标注需要的值,0标注不要的值。因为1与任何数做与运算都得任何数,0与任何数做与运算都得0)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">private</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> MODE_MASK = </span><span class="number">0x3</span><span> << MODE_SHIFT; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 0向左进位30,就是00 00000000000(00后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> UNSPECIFIED = </span><span class="number">0</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> <span class="comment">// 1向左进位30,就是01 00000000000(01后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> EXACTLY = </span><span class="number">1</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> <span class="comment">// 2向左进位30,就是10 00000000000(10后跟30个0)</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">int</span><span> AT_MOST = </span><span class="number">2</span><span> << MODE_SHIFT; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 根据提供的size和mode得到一个详细的测量结果</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// measureSpec = size + mode; (注意:二进制的加法,不是10进制的加法!)</span><span> </span></span></li><li><span> <span class="comment">// 这里设计的目的就是使用一个32位的二进制数,32和31位代表了mode的值,后30位代表size的值</span><span> </span></span></li><li class="alt"><span> <span class="comment">// 例如size=100(4),mode=AT_MOST,则measureSpec=100+10000...00=10000..00100</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> makeMeasureSpec(</span><span class="keyword">int</span><span> size, </span><span class="keyword">int</span><span> mode) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> size + mode; </span></span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 通过详细测量结果获得mode</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// mode = measureSpec & MODE_MASK;</span><span> </span></span></li><li><span> <span class="comment">// MODE_MASK = 11 00000000000(11后跟30个0),原理是用MODE_MASK后30位的0替换掉measureSpec后30位中的1,再保留32和31位的mode值。</span><span> </span></span></li><li class="alt"><span> <span class="comment">// 例如10 00..00100 & 11 00..00(11后跟30个0) = 10 00..00(AT_MOST),这样就得到了mode的值</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getMode(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> (measureSpec & MODE_MASK); </span></span></li><li><span> } </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">/**</span> </span></li><li class="alt"><span><span class="comment"> * 通过详细测量结果获得size</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="comment">// size = measureSpec & ~MODE_MASK;</span><span> </span></span></li><li><span> <span class="comment">// 原理同上,不过这次是将MODE_MASK取反,也就是变成了00 111111(00后跟30个1),将32,31替换成0也就是去掉mode,保留后30位的size</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getSize(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li><span> <span class="keyword">return</span><span> (measureSpec & ~MODE_MASK); </span></span></li><li class="alt"><span> } </span></li><li><span> </span></li><li class="alt"><span> <span class="comment">/**</span> </span></li><li><span><span class="comment"> * 重写的toString方法,打印mode和size的信息,这里省略</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> String toString(</span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">return</span><span> </span><span class="keyword">null</span><span>; </span></span></li><li><span> } </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong><br>
</strong></span></span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong>源码中的onMeasure()</strong></span><span style="font-family:Arial; font-size:24px; color:#cc00; line-height:26px"><strong>:</strong></span><br>
</span></p>
<p><span style="font-size:18px"><span style="font-family:Arial; color:#333333; line-height:26px">知道了widthMeasureSpec和heightMeasureSpec是什么以后</span><span style="font-family:Arial; color:#333333; line-height:26px">,我们就可以来看onMeasure方法了:</span></span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 2691px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_2" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=2&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 这个方法需要被重写,应该由子类去决定测量的宽高值,</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), </span></li><li><span> getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-size:18px">在onMeasure中只调用了setMeasuredDimension()方法,接受两个参数,这两个参数是通过<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize方法得到的,我们到源码里看看<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize究竟做了什么</span></span>。</span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><strong><span style="font-size:24px; color:#cc0000">getDefaultSize():</span></strong></span><br>
</span></p>
<p><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 2976px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_3" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=3&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 作用是返回一个默认的值,如果MeasureSpec没有强制限制的话则使用提供的大小.否则在允许范围内可任意指定大小</span> </span></li><li class="alt"><span><span class="comment"> * 第一个参数size为提供的默认大小,第二个参数为测量的大小</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span> <span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getDefaultSize(</span><span class="keyword">int</span><span> size, </span><span class="keyword">int</span><span> measureSpec) { </span></span></li><li><span> <span class="keyword">int</span><span> result = size; </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> specMode = MeasureSpec.getMode(measureSpec); </span></span></li><li><span> <span class="keyword">int</span><span> specSize = MeasureSpec.getSize(measureSpec); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="keyword">switch</span><span> (specMode) { </span></span></li><li class="alt"><span> <span class="comment">// Mode = UNSPECIFIED,AT_MOST时使用提供的默认大小</span><span> </span></span></li><li><span> <span class="keyword">case</span><span> MeasureSpec.UNSPECIFIED: </span></span></li><li class="alt"><span> result = size; </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.AT_MOST: </span></span></li><li><span> <span class="comment">// Mode = EXACTLY时使用测量的大小 </span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.EXACTLY: </span></span></li><li><span> result = specSize; </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li><span> } </span></li><li class="alt"><span> <span class="keyword">return</span><span> result; </span></span></li><li><span> } </span></li></ol>
</div>
<span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-size:18px">getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),这里就是获取最小宽度作为默认值,然后再根据具体的测量值和选用的模式来得到<span style="color:rgb(51,51,51); font-family:Arial; line-height:26px">widthMeasureSpec。<span style="font-family:Arial; color:#333333; line-height:26px">heightMeasureSpec同理。之后将<span style="font-family:Arial; color:#333333; line-height:26px">widthMeasureSpec,</span><span style="font-family:Arial; color:#333333; line-height:26px">heightMeasureSpec传入<span style="font-family:Arial; color:#333333; line-height:26px">setMeasuredDimension()方法。</span></span></span></span></span></span>
<p><span style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><span style="color:rgb(51,51,51); font-family:Arial; font-size:14px; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><span style="font-family:Arial; font-size:14px; color:#333333; line-height:26px"><br>
</span></span></span></span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-family:Arial; line-height:26px"><span style="font-size:24px; color:#cc0000"><strong>setMeasuredDimension():</strong></span></span></span></span></span></span></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 3634px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_4" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=4&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 这个方法必须由onMeasure(int, int)来调用,来存储测量的宽,高值。</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">final</span><span> </span><span class="keyword">void</span><span> setMeasuredDimension(</span><span class="keyword">int</span><span> measuredWidth, </span><span class="keyword">int</span><span> measuredHeight) { </span></span></li><li class="alt"><span> mMeasuredWidth = measuredWidth; </span></li><li><span> mMeasuredHeight = measuredHeight; </span></li><li class="alt"><span> </span></li><li><span> mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; </span></li><li class="alt"><span>} </span></li></ol>
</div>
<span style="font-size:18px">这个方法就是我们重写onMeasure()所要实现的最终目的。它的作用就是存储我们测量好的宽高值。</span>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">这下思路清晰了,现在的任务就是<span style="font-family:Arial; color:#333333; line-height:26px">计算出准确</span>的measuredWidth和heightMeasureSpec并传递进去,我们所有<span style="font-family:Arial; color:#333333; line-height:26px">的测量任务就算完成了。</span></span></span></p>
<p><span style="color:rgb(51,51,51); font-family:Arial; line-height:26px"><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px">源码中使用的<span style="font-family:Arial; color:#333333; line-height:26px">getDefaultSize()只是简单的测量了宽高值,在实际使用时需要精细、具体的测量。而</span>具体的测量任务就交给我们在子类中重写的onMeasure方法。</span></span></span></p>
<p><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-family:Arial; color:#333333; line-height:26px"><span style="font-size:18px"><br>
</span></span></span></p>
<p><span style="font-family:Arial; line-height:26px"><span style="font-size:24px; color:#cc00"><strong>在子类中重写的onMeasure:</strong></span></span></p>
<p><span style="font-size:18px">在测量之前首先要明确一点,需要测量的是一个View(例如TextView),还是一个ViewGroup(例如LinearLayout),还是多个ViewGroup嵌套。如果只有一个View的话我们就测量这一个就可以了,如果有多个View或者ViewGroup嵌套我们就需要循环遍历视图中所有的View。</span></p>
<p><span style="font-size:18px">下面列出一个最简单的小例子,写一个自定义类CostomViewGroup继承自ViewGroup,然后重写它的构造方法,onMeasure和onLayout方法。用这个自定义的ViewGroup去写一个布局文件如下:</span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 4331px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_5" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=5&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span><com.gxy.text.CostomViewGroup xmlns:android=</span><span class="string">"http://schemas.android.com/apk/res/android"</span><span> </span></span></li><li><span> android:layout_width=<span class="string">"match_parent"</span><span> </span></span></li><li class="alt"><span> android:layout_height=<span class="string">"match_parent"</span><span> </span></span></li><li><span> android:background=<span class="string">"#bbbaaa"</span><span> </span></span></li><li class="alt"><span> > </span></li><li><span> <Button </span></li><li class="alt"><span> android:text=<span class="string">"@string/hello_world"</span><span> </span></span></li><li><span> android:layout_width=<span class="string">"match_parent"</span><span> </span></span></li><li class="alt"><span> android:layout_height=<span class="string">"wrap_content"</span><span> </span></span></li><li><span> android:background=<span class="string">"#aaabbb"</span><span> </span></span></li><li class="alt"><span> android:id=<span class="string">"@+id/textView1"</span><span> /> </span></span></li><li><span></com.gxy.text.CostomViewGroup> </span></li></ol>
</div>
<span style="font-size:18px">将一个Button放入自定义的ViewGroup中,然后在MainActivity的onCreate回调方法中调用setContentView把整个布局文件设置进去。</span>
<p><span style="font-size:18px">最后看一下自定义CostomViewGroup中的onMeasure方法的内容:</span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 4704px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_6" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=6&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="annotation">@Override</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> onMeasure(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//调用ViewGroup类中测量子类的方法</span><span> </span></span></li><li class="alt"><span> measureChildren(widthMeasureSpec, heightMeasureSpec); </span></li><li><span> <span class="comment">//调用View类中默认的测量方法</span><span> </span></span></li><li class="alt"><span> <span class="keyword">super</span><span>.onMeasure(widthMeasureSpec,heightMeasureSpec); </span></span></li><li><span> </span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-size:18px">本文只是介绍测量,所以onLayout方法先省略,下面来看看效果图:</span></p>
<p><img src="http://img.blog.csdn.net/20140716223856156?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<span style="font-size:18px">在子类重写的onMeasure中只调用两个方法,第一个是父类的onMeasure方法,之前已经介绍了它的作用,它最后会调用<span style="font-family:Arial; color:#333333; line-height:26px">setMeasuredDimension()将测量好的宽高值传递进去。第二个会调用measureChildren方法,它的作用是测量所有的子View,下面我们看看它是如何工作的。</span></span>
<p><span style="font-size:24px; color:#cc00"><strong>measureChildren()</strong></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 5705px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_7" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_7" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=7&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span> </span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 遍历所有的子view去测量自己(跳过GONE类型View)</span> </span></li><li class="alt"><span><span class="comment"> * @param widthMeasureSpec 父视图的宽详细测量值</span> </span></li><li><span><span class="comment"> * @param heightMeasureSpec 父视图的高详细测量值</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> measureChildren(</span><span class="keyword">int</span><span> widthMeasureSpec, </span><span class="keyword">int</span><span> heightMeasureSpec) { </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> size = mChildrenCount; </span></span></li><li><span> <span class="keyword">final</span><span> View[] children = mChildren; </span></span></li><li class="alt"><span> <span class="keyword">for</span><span> (</span><span class="keyword">int</span><span> i = </span><span class="number">0</span><span>; i < size; ++i) { </span></span></li><li><span> <span class="keyword">final</span><span> View child = children[i]; </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> ((child.mViewFlags & VISIBILITY_MASK) != GONE) { </span></span></li><li><span> measureChild(child, widthMeasureSpec, heightMeasureSpec); </span></li><li class="alt"><span> } </span></li><li><span> } </span></li><li class="alt"><span>} </span></li></ol>
</div>
<span style="font-size:18px">代码很简单,就是遍历所有的子View,如果View的状态不是GONE就调用measureChild去进行下一步的测量</span>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>measureChild()</strong></span><br>
</p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 6170px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_8" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_8" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=8&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 测量单个视图,将宽高和padding加在一起后交给getChildMeasureSpec去获得最终的测量值</span> </span></li><li class="alt"><span><span class="comment"> * @param child 需要测量的子视图</span> </span></li><li><span><span class="comment"> * @param parentWidthMeasureSpec 父视图的宽详细测量值</span> </span></li><li class="alt"><span><span class="comment"> * @param parentHeightMeasureSpec 父视图的高详细测量值</span> </span></li><li><span><span class="comment"> */</span><span> </span></span></li><li class="alt"><span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> measureChild(View child, </span><span class="keyword">int</span><span> parentWidthMeasureSpec, </span></span></li><li><span> <span class="keyword">int</span><span> parentHeightMeasureSpec) { </span></span></li><li class="alt"><span> <span class="comment">// 取得子视图的布局参数</span><span> </span></span></li><li><span> <span class="keyword">final</span><span> LayoutParams lp = child.getLayoutParams(); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 通过getChildMeasureSpec获取最终的宽高详细测量值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, </span></span></li><li><span> mPaddingLeft + mPaddingRight, lp.width); </span></li><li class="alt"><span> <span class="keyword">final</span><span> </span><span class="keyword">int</span><span> childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, </span></span></li><li><span> mPaddingTop + mPaddingBottom, lp.height); </span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 将计算好的宽高详细测量值传入measure方法,完成最后的测量</span><span> </span></span></li><li class="alt"><span> child.measure(childWidthMeasureSpec, childHeightMeasureSpec); </span></li><li><span>} </span></li></ol>
</div>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>getChildMeasureSpec()</strong></span></p>
<div class="dp-highlighter bg_java">
<div class="bar">
<div class="tools"><strong>[java]</strong> <a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="ViewSource" title="view plain">
view plain</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="CopyToClipboard" title="copy">copy</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="PrintSource" title="print">print</a><a target="_blank" href="http://blog.csdn.net/a396901990/article/details/36475213#" class="About" title="?">?</a><a target="_blank" href="https://code.csdn.net/snippets/428404" title="在CODE上查看代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/CODE_ico.png" alt="在CODE上查看代码片" height="12" width="12" style="position:relative; top:1px; left:2px"></a><a target="_blank" href="https://code.csdn.net/snippets/428404/fork" title="派生到我的代码片" style="text-indent:0"><img src="https://code.csdn.net/assets/ico_fork.svg" alt="派生到我的代码片" height="12" width="12" style="position:relative; top:2px; left:2px"></a><div style="position: absolute; left: 514px; top: 6658px; width: 18px; height: 18px; z-index: 99;"><embed id="ZeroClipboardMovie_9" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="18" height="18" name="ZeroClipboardMovie_9" align="middle" allowscriptaccess="always" allowfullscreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="id=9&width=18&height=18" wmode="transparent"></div></div>
</div>
<ol class="dp-j" start="1">
<li class="alt"><span><span class="comment">/**</span> </span></li><li><span><span class="comment"> * 在measureChildren中最难的部分:找出传递给child的MeasureSpec。</span> </span></li><li class="alt"><span><span class="comment"> * 目的是结合父view的MeasureSpec与子view的LayoutParams信息去找到最好的结果</span> </span></li><li><span><span class="comment"> * (也就是说子view的确切大小由两方面共同决定:1.父view的MeasureSpec 2.子view的LayoutParams属性)</span> </span></li><li class="alt"><span><span class="comment"> * </span> </span></li><li><span><span class="comment"> * @param spec 父view的详细测量值(MeasureSpec)</span> </span></li><li class="alt"><span><span class="comment"> * @param padding view当前尺寸的的内边距和外边距(padding,margin)</span> </span></li><li><span><span class="comment"> * @param childDimension child在当前尺寸下的布局参数宽高值(LayoutParam.width,height)</span> </span></li><li class="alt"><span><span class="comment"> */</span><span> </span></span></li><li><span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getChildMeasureSpec(</span><span class="keyword">int</span><span> spec, </span><span class="keyword">int</span><span> padding, </span><span class="keyword">int</span><span> childDimension) { </span></span></li><li class="alt"><span> <span class="comment">//父view的模式和大小</span><span> </span></span></li><li><span> <span class="keyword">int</span><span> specMode = MeasureSpec.getMode(spec); </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> specSize = MeasureSpec.getSize(spec); </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">//通过父view计算出的子view = 父大小-边距(父要求的大小,但子view不一定用这个值) </span><span> </span></span></li><li><span> <span class="keyword">int</span><span> size = Math.max(</span><span class="number">0</span><span>, specSize - padding); </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//子view想要的实际大小和模式(需要计算)</span><span> </span></span></li><li class="alt"><span> <span class="keyword">int</span><span> resultSize = </span><span class="number">0</span><span>; </span></span></li><li><span> <span class="keyword">int</span><span> resultMode = </span><span class="number">0</span><span>; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">//通过1.父view的MeasureSpec 2.子view的LayoutParams属性这两点来确定子view的大小</span><span> </span></span></li><li class="alt"><span> <span class="keyword">switch</span><span> (specMode) { </span></span></li><li><span> <span class="comment">// 当父view的模式为EXACITY时,父view强加给子view确切的值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.EXACTLY: </span></span></li><li><span> <span class="comment">// 当子view的LayoutParams>0也就是有确切的值</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> <span class="comment">//子view大小为子自身所赋的值,模式大小为EXACTLY</span><span> </span></span></li><li class="alt"><span> resultSize = childDimension; </span></li><li><span> resultMode = MeasureSpec.EXACTLY; </span></li><li class="alt"><span> <span class="comment">// 当子view的LayoutParams为MATCH_PARENT时(-1)</span><span> </span></span></li><li><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li class="alt"><span> <span class="comment">//子view大小为父view大小,模式为EXACTLY</span><span> </span></span></li><li><span> resultSize = size; </span></li><li class="alt"><span> resultMode = MeasureSpec.EXACTLY; </span></li><li><span> <span class="comment">// 当子view的LayoutParams为WRAP_CONTENT时(-2) </span><span> </span></span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> <span class="comment">//子view决定自己的大小,但最大不能超过父view,模式为AT_MOST</span><span> </span></span></li><li class="alt"><span> resultSize = size; </span></li><li><span> resultMode = MeasureSpec.AT_MOST; </span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> </span></li><li><span> <span class="comment">// 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。</span><span> </span></span></li><li class="alt"><span> <span class="keyword">case</span><span> MeasureSpec.AT_MOST: </span></span></li><li><span> <span class="comment">// 道理同上</span><span> </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> resultSize = childDimension; </span></li><li class="alt"><span> resultMode = MeasureSpec.EXACTLY; </span></li><li><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li class="alt"><span> resultSize = size; </span></li><li><span> resultMode = MeasureSpec.AT_MOST; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> resultSize = size; </span></li><li class="alt"><span> resultMode = MeasureSpec.AT_MOST; </span></li><li><span> } </span></li><li class="alt"><span> <span class="keyword">break</span><span>; </span></span></li><li><span> </span></li><li class="alt"><span> <span class="comment">// 当父view的模式为UNSPECIFIED时,子view为想要的值</span><span> </span></span></li><li><span> <span class="keyword">case</span><span> MeasureSpec.UNSPECIFIED: </span></span></li><li class="alt"><span> <span class="keyword">if</span><span> (childDimension >= </span><span class="number">0</span><span>) { </span></span></li><li><span> <span class="comment">// 子view大小为子自身所赋的值</span><span> </span></span></li><li class="alt"><span> resultSize = childDimension; </span></li><li><span> resultMode = MeasureSpec.EXACTLY; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.MATCH_PARENT) { </span></span></li><li><span> <span class="comment">// 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0</span><span> </span></span></li><li class="alt"><span> resultSize = <span class="number">0</span><span>; </span></span></li><li><span> resultMode = MeasureSpec.UNSPECIFIED; </span></li><li class="alt"><span> } <span class="keyword">else</span><span> </span><span class="keyword">if</span><span> (childDimension == LayoutParams.WRAP_CONTENT) { </span></span></li><li><span> <span class="comment">// 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0</span><span> </span></span></li><li class="alt"><span> resultSize = <span class="number">0</span><span>; </span></span></li><li><span> resultMode = MeasureSpec.UNSPECIFIED; </span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">break</span><span>; </span></span></li><li class="alt"><span> } </span></li><li><span> <span class="keyword">return</span><span> MeasureSpec.makeMeasureSpec(resultSize, resultMode); </span></span></li><li class="alt"><span>} </span></li></ol>
</div>
<p><span style="font-size:18px">可能看完后感觉有点迷糊,接下来通过几个例子演示一下,可能大家就会对getChildMeasureSpec方法中的逻辑清晰一些。</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px">1.当父类View中宽高都为MATCH_PARENT(EXACTLY)时,宽高都为MATCH_PARENT(EXACTLY)时:</span></p>
<p><span style="font-size:18px">2.当父类View中宽高都为MATCH_PARENT(EXACTLY)时,宽高都为WRAP_CONTENT(EXACTLY)时:<br>
</span></p>
<p><span style="font-size:18px">3.当父类View中宽高都为MATCH_PARENT(EXACTLY)时。子类宽WRAP_CONTENT(AT_MOST),高为MATCH_PARENT(EXACTLY)时:</span><br>
</p>
<p><img src="http://img.blog.csdn.net/20140716232208687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><img src="http://img.blog.csdn.net/20140716233105536?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><img src="http://img.blog.csdn.net/20140716232846593?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""><br>
</p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px">1.当父类View中宽高都为WRAP_CONTENT(AT_MOST)时,子类宽高都为MATCH_PARENT(EXACTLY)时:</span></p>
<p><span style="font-size:18px">2.当父类View中宽高都为WRAP_CONTENT(AT_MOST)时。子类宽WRAP_CONTENT(AT_MOST),高为MATCH_PARENT(EXACTLY)时:</span></p>
<p><img src="http://img.blog.csdn.net/20140716233403002?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""> <img src="http://img.blog.csdn.net/20140717002350329?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYTM5NjkwMTk5MA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt=""></p>
<p><span style="font-size:18px">通过这两组简单的对比,其实大家就可以把测量子类大小的代码理解为:</span></p>
<p><span style="font-size:18px">父类中MATCH_PARENT,WRAP_CONTENT,指定值和子类中的MATCH_PARENT,WRAP_CONTENT,指定值这两对值的相互作用。</span></p>
<p><span style="font-size:18px">更复杂的情况则需要加上padding内边距和margin外边距等等一些其他对于View大小的约束。</span></p>
<p><br>
</p>
<p><span style="font-size:24px; color:#cc0000"><strong>总结:</strong></span></p>
<p><span style="font-size:18px">今天介绍的都是系统提供的测量方法,除了这些以外还有一些其他的,大家可以看看源码。而且在真正的自定义View视图时,很大一部分都是借助这些系统提供的现成方法,并且根据需求再加上自己的特殊逻辑(当然也可以全部用自己的逻辑,但我们不要重复制造轮子)。</span></p>
<p><span style="font-size:18px">这篇文章写了2个礼拜,写之前思路非常清晰,但是在写的时候越写越乱。写完以后感觉逻辑仍然不是很清晰,因为有的内容我也是一知半解比如UNSPECIFIED。如果大家水平和我差不多都是菜鸟级别的,希望大家不要深入的去研究源码逻辑,这样会导致越来越来混乱,从应用的角度出发可能会更好一些。</span></p>
<p><span style="font-size:18px">下面会接着写onLayout和LayoutParams的相关内容。最后再将onMeasure,onLayout结合起来写一个完整的例子。也许这些都写完以后会对整个流程的思路会更加清晰。</span></p>
<p><span style="font-size:18px">来源:http://blog.csdn.net/a396901990/article/details/36475213</span></p>
<p><span style="font-size:18px"><br>
</span></p>
</div>
<!-- Baidu Button BEGIN -->
<div class="bdsharebuttonbox bdshare-button-style0-16" style="float: right;" data-bd-bind="1411716159256">
<a href="#" class="bds_more" data-cmd="more" style="background-position:0 0 !important; background-image: url(http://bdimg.share.baidu.com/static/api/img/share/icons_0_16.png?v=d754dcc0.png) !important"></a>
<a href="#" class="bds_qzone" data-cmd="qzone" title="分享到QQ空间" style="background-position:0 -52px !important"></a>
<a href="#" class="bds_tsina" data-cmd="tsina" title="分享到新浪微博" style="background-position:0 -104px !important"></a>
<a href="#" class="bds_tqq" data-cmd="tqq" title="分享到腾讯微博" style="background-position:0 -260px !important"></a>
<a href="#" class="bds_renren" data-cmd="renren" title="分享到人人网" style="background-position:0 -208px !important"></a>
<a href="#" class="bds_weixin" data-cmd="weixin" title="分享到微信" style="background-position:0 -1612px !important"></a>
</div>
<script>window._bd_share_config = { "common": { "bdSnsKey": {}, "bdText": "", "bdMini": "1", "bdMiniList": false, "bdPic": "", "bdStyle": "0", "bdSize": "16" }, "share": {} }; with (document) 0[(getElementsByTagName('head')[0] || body).appendChild(createElement('script')).src = 'http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion=' + ~(-new Date() / 36e5)];</script>
<!-- Baidu Button END -->
<!--192.168.100.35-->
<ul class="article_next_prev">
<li class="prev_article"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shangyipian']);location.href='/easyer2012/article/details/37872457';">上一篇</span><a href="/easyer2012/article/details/37872457" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_shangyipian'])">Android UI开发第二十四篇——Action Bar</a></li>
<li class="next_article"><span onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_xiayipian']);location.href='/easyer2012/article/details/38346695';">下一篇</span><a href="/easyer2012/article/details/38346695" onclick="_gaq.push(['_trackEvent','function', 'onclick', 'blog_articles_xiayipian'])">log4j使用简介</a></li>
</ul>
<!-- Baidu Button BEGIN -->
<script type="text/javascript" id="bdshare_js" data="type=tools&uid=1536434" src="http://bdimg.share.baidu.com/static/js/bds_s_v2.js?cdnversion=392144"></script>
<script type="text/javascript">
document.getElementById("bdshell_js").src = "http://bdimg.share.baidu.com/static/js/shell_v2.js?cdnversion=" + Math.ceil(new Date()/3600000)
</script>
<!-- Baidu Button END -->
</div>
0 0
- 自定义view 重写onMeasure()方法
- 自定义view onMeasure方法的重写
- 自定义View-2-重写onMeasure
- 自定义View中为什么需要重写onMeasure()方法?
- 重写View的onMeasure方法
- 自定义View-onMeasure()方法
- 自定义View之onMeasure方法
- 自定义View之onMeasure()方法
- Android自定义View-------为什么重写onMeasure()以及怎么重写
- Android自定义View-------为什么重写onMeasure()以及怎么重写
- 纯粹自定义view即继承view(重写onMeasure() onDraw())
- View绘制---onMeasure()重写
- Android 自定义 View 之 onMeasure() 源码分析及重写
- Android自定义View之onMeasure()源码分析及重写
- 自定义View的onMeasure方法理解
- Android 自定义view 和 onMeasure方法介绍
- Android 自定义view 和 onMeasure方法介绍
- 自定义view,viewgroup的onMeasure 方法
- ASP.NET MVC Action Filters
- java.lang.NoClassDefFoundError: org/apache/juli/logging/LogFactory
- 自定义ZBAR,二维码扫描
- Xilinx FPGA ML605 开发笔记——跑马灯程序
- 使用BeanUtils.copyproperties发生 No value specified for 'Date'异常
- 自定义view 重写onMeasure()方法
- Oracle非关键文件恢复,日志成员、临时文件、索引表空间、口令文件(密码文件)
- 动态规划:从新手到专家
- PHPCMS 的Ajax 分页
- linux 下C程序内存分布
- No identities are available for signing的解决方法
- 【开源库大全】八、BlurEffectForAndroidDesign
- 关于airplay协议实现镜像功能研究
- Entity Framework 技术