<a href="http://www.cnblogs.com/sunshine-anycall/p/5448108.html">Android自定義視圖一:擴充現有的視圖,添加新的XML屬性</a>
<a href="http://www.cnblogs.com/sunshine-anycall/p/5460023.html">Android自定義視圖二:如何繪制内容</a>
<a href="http://www.cnblogs.com/sunshine-anycall/p/5466067.html">Android自定義視圖三:給自定義視圖添加“流暢”的動畫</a>
<a href="http://www.cnblogs.com/sunshine-anycall/p/5470984.html">Android自定義視圖四:定制onMeasure強制顯示為方形</a>

上一篇開發之後的效果如上圖。不過看着這張圖,需要注意的不是我們自定義視圖展示了什麼,而是這個視圖的大小和位置。你會看到這個折線圖有一個特定的大小(size)。這個size是怎麼定的呢?現在的代碼是使用了一個豎直方向的<code>LinearLayout</code>,折線圖和他下面的<code>TextView</code>使用<code>layout_weight</code>屬性平分了他們所在的<code>LinearLayout</code>的高度。那麼如果我們删掉了<code>TextView</code>和全部的<code>layout_weight</code>,并把折線圖的高度設定為<code>wrap_content</code>會發生什麼呢?
是的,以上修改之後整個的圖就變成了這樣。雖然使用了<code>wrap_content</code>的高度,但是效果是填滿了整個<code>LinearLayout</code>。這就是View的預設布局行為,但是,如果我們要改變一下呢?
自定義視圖顯示在螢幕上一共分三步:measure(測量),layout(布局),draw(繪制)。基本上一個自定義視圖在測量這一步計算大小,之後可以通過<code>getMeasureWidth</code>和<code>getMeasureHeight</code>得到View的寬度和高度。在布局計算這個自定義視圖的左上和右下坐标以及實際的寬度和高度,最後根據以上layout步驟獲得的資料調用<code>onDraw</code>方法把View繪制在螢幕上。
是以要修改size,也就是自定義視圖中修改預設的行為,就需要override <code>onMeasure()</code>方法。一般的通用做法是:
簡單了解<code>MeasureSpec.AT_MOST</code>就是你給折線圖的<code>layout_width</code>或者<code>layout_height</code>設定了<code>wrap_content</code>,系統不知道精确的寬度、高度是多少的時候的一個标記。如果有具體的50dp, 100dp的時候,這個标記的值為<code>MeasureSpec.EXACTLY</code>。一般,一個view的寬度、高度隻有這兩種标記。
View的寬、高度測量分别處理三種情況:
如果寬、高度都是<code>AT_MOST</code>的時候,寬度和高度設定為預設值。
寬度為<code>AT_MOST</code>高度不是的時候,寬度設定為預設值,高度設定為測量的值<code>heightSpecSize</code>。
寬度為精确值,高度為<code>AT_MOST</code>的時候,寬度設定為<code>widthSpecSize</code>,高度設定為預設值。
而我們這裡則是意外的簡單。因為要設定為正方形,是以使用寬度和高度中相對較小的那個值來作為寬、高度共同的值就可以了:
如前文所說,我們要把折線圖這個自定義視圖設定為正方形。是以,不管測量的Mode是如何的,隻要用寬、高中的最小值就可以了。
我們前面在<code>onDraw</code>方法使用的<code>getWidth()</code>和<code>getHeight()</code>在<code>onMeasure()</code>方法中都是不可用的。因為這個時候正在計算寬、高度。在這個方法裡隻能取到<code>getMeasuredWidth()</code>和<code>getMeasuredHeight()</code>。
override <code>onMeasure</code>方法就一定要在最後調用<code>setMeasuredDimension</code>方法。調用<code>setMeasuredDimension</code>方法是告訴父view目前view的測量高度是多少。如果不調用這個方法的話會抛異常。
修改之後的布局,寬度<code>match_parent</code>,高度<code>wrap_content</code>。不必要的屬性都略掉了。
效果:
一個正方形的View已經非常實用了。比如繼承<code>ImageView</code>之後像上面一樣override了<code>onMeasure()</code>方法就可以得到一個一直都是正方形顯示的View。那麼,既然我們已經支援了寬、高1:1了,為什麼不支援任意的寬高比呢。
上面的代碼就可以支援任意的寬高比了。看看效果(比例7:3):
本文轉自張昺華-sky部落格園部落格,原文連結:http://www.cnblogs.com/sunshine-anycall/p/5470984.html,如需轉載請自行聯系原作者