標籤:
問題:給MyView設定預設寬高的話,在measure的過程中mode變為EXACTLY,而且不能自適應content的大小。查看TextView的源碼,發現其中不僅是對三種模式進行單獨處理,而且還讓AT_MOST做了自適應content,這個問題有點複雜,留待以後解決
View的測量會回調onMeasure方法,因此首先要複寫onMeasure方法,這個方法的作用進行寬高的測量,然後必須調用setMeasuredDimension進行設定,不然會觸發IllegalStateException異常
不複寫此方法,預設採用EXACTLY模式測量,而EXACTLY只支援match_parent和指定的尺寸,指定為wrap_content的話無效,因為wrap_content要有一個預設值,因此系統會直接設定成match_parent.
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec,heightMeasureSpec);}
系統回調onMeasure的時候,是從布局檔案中讀取寬高的設定,比如指定match_parent和具體尺寸的話,顯然這裡的mode為EXACTLY,MeasureSpec這裡不贅述,官網解釋View.MeasureSpec,這種情況下不需要我們處理,因為符合預設的測量模式。
但是我們如果希望控制項自適應內容呢?即wrap_content。又該怎麼辦呢?前面已經提到在布局檔案設定wrap_content無效,大家可以自己測試一下。
解決辦法:之所以設定無效,是因為在onMeasure的時候,預設以EXACTLY來處理,那麼我們只要自己寫一個測量方法就可以了。
下面給出了測量寬和高的兩個方法
measureWidth和measureHeight,只需要在模式不是EXACTLY的時候進行處理就可以了
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec)); } private int measureWidth(int widthMeasureSpec) { Log.i("measureWidth"," "+MeasureSpec.toString(widthMeasureSpec)); int result=200;//指定預設大小 if((MeasureSpec.getMode(widthMeasureSpec)!=MeasureSpec.EXACTLY)){ result = Math.min(result,MeasureSpec.getSize(widthMeasureSpec)); return result; } return MeasureSpec.getSize(widthMeasureSpec); } private int measureHeight(int heightMeasureSpec) { Log.i("measureHeight"," "+MeasureSpec.toString(heightMeasureSpec)); int result=200;//指定預設大小 if((MeasureSpec.getMode(heightMeasureSpec)!=MeasureSpec.EXACTLY)){ result = Math.min(result,MeasureSpec.getSize(heightMeasureSpec)); return result; } return MeasureSpec.getSize(heightMeasureSpec); }
日誌:
通過日誌發現,開始的測量模式為AT_MOST,因為我們設定的是wrap_content,然後再自己定義的測量方法中指定了預設大小,因此變為了EXACTLY。
效果:
實現自己的測量方法前
實現自己的測量方法後
可以看到實現自己的方法後,wrap_content變得有效,預設值為200dp。
Android Notes 之 View篇(1) View的測量