Android開發(fā)中經常需要獲取控件的寬高剧蹂,比如前不久我在寫一個圖片加載庫時信卡,因為需要對Bitmap進行裁剪就遇到了需要獲取ImageView寬高的問題。
如果稍微了解過一下View
的繪制過程,就會知道直接在onCreate()
等生命周期回調方法中獲取寬高抑诸,獲取到的值是0,所以我們需要采用一些特殊的方法去獲取爹殊。
這里簡單總結一下獲取寬高的幾種方法:
一蜕乡、通過View.post(new Runnable())獲取
這里的view可以是你需要獲取寬高的View。要注意的是view
要執(zhí)行此方法必須保證它已經attached到了window上梗夸,因此在此之前是不能調用這個方法的层玲。
在Runnable
里可以執(zhí)行獲取寬高的方法:
view.post(new Runnable(){
@Override
public void run() {
int width = view.getMeasuredWidth();
int height = view.getMeasuredHeight();
}
});
這個方法的原理在于:View
的寬高需要在Measure
過程后才能確定,直接在onCreate()
等回調方法里獲取只能得到0反症,因為此時還沒有開始Measure
操作称簿。
而通過view.post()
在主線程的消息隊列尾部插入了一個消息,也就是說執(zhí)行獲取寬高的操作被延后了惰帽,并且能夠保證Measure
操作在此之前憨降,所以就能夠在這里獲取到正確的寬高了。
有關為什么“能夠保證Measure
操作在此之前”该酗,我會在下一篇文章里詳細分析授药。
另外,在網上還可以搜到其他類似方法如使用
ViewTreeObserver.addOnGlobalLayout()/addOnPreDrawLayout()
或Activity/View.onWindowFocusChanged()
方法中獲取的呜魄,本質也是延后了操作悔叽,等待View
初始化完畢了之后再進行獲取,在這里就不細說了爵嗅。
總結:
此方法優(yōu)點是保證獲取到的寬高是準確的娇澎;
缺點是不能及時獲取到,實際上還是把操作延后了睹晒,需要在Runnable
里再執(zhí)行相應回調趟庄。
二括细、通過LayoutParams獲取
對于在XML
文件里設置了具體寬高的View
可以通過view.getLayoutParams().height/width
獲取到寬高。
總結:優(yōu)點是能及時獲取到戚啥,且操作簡單奋单;缺點是不夠通用,沒有設置具體寬高的獲取到的值就是0了猫十。
三览濒、手動Measure再獲取
既然View
的寬高是在Measure
之后才能獲得的,自行調用view.measure()
不就行了嗎拖云?
那么我們需要自行構造MeasureSpec
,也就是測量參數贷笛,它是一個由父容器和View
自身決定的變量。有關它的具體分析宙项,可以閱讀《Android開發(fā)藝術探索》來了解乏苦。
對于寬高設為具體數值或wrap_content
的控件,我們都可以手動構造MeasureSpec
杉允,而match_parent
的情況理論上是做不到的。
對于設置了具體數值寬高的(比如都是100px)席里,我們可以這樣構造MeasureSpec
:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100,MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec,heightMeasureSpec);
對于設置成wrap_content
的:
int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOTST);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1<<30)-1,MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec,heightMeasureSpec);
總結:優(yōu)點也是可以立即獲取到寬高叔磷;缺點是無法解決match_parent
的情況。