在Android開發(fā)中,有時需要對控件進(jìn)行測量,得到的控件寬度和高度可以用來做一些計算。在需要自適應(yīng)屏幕的情況下,這種計算就顯得特別重要。另一方便,由于需求的原因,希望一進(jìn)入界面后,就能得到控件的寬度和高度。
實際上在onCreate、onStart、onResume中無法正確得到某個view的寬高信息,這是因為View的measure過程和activity的生命周期方法不是同步執(zhí)行的,因此無法保證Activity執(zhí)行了上述方法時某個view已經(jīng)測量完畢了,如果view還沒有測
量完畢,那么獲取的寬高就是0,下面提供四種方法來解決這個問題:
(1) Activity/View---onWindowFoucusChanged:
onWindowFoucsChanged這個方法的含義是:view已經(jīng)初始化完畢,寬/高已經(jīng)準(zhǔn)備好了,這個時候去獲取是沒問題
的。需要注意的是onWindowFocusChanged會被調(diào)用多次,當(dāng)activity的窗口得到焦點和失去焦點時均會被調(diào)用。
代碼如下:
@Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if(hasFocus){ int width = view.getMeasureWidth(); int height = view.getMeausreHeight(); }}(2) view.post(runnable):
通過post可以將一個runnable投遞到消息隊列的尾部,然后等待looper調(diào)用次runnable的時候,view也已經(jīng)初始化好了:
代碼如下:@Override PRotected void onStart() { super.onStart(); view.post(new Runnable(){ @Override public void run() { int width = view.getMEasureWidth(); int height = view.getMeasureHeight(); } });}(3) ViewTreeObserver:
使用ViewTreeObserver的眾多回調(diào)可以完成這個功能,比如使用OnGlobalLayoutListener這個接口,當(dāng)view樹狀態(tài)發(fā)
生改變或者view樹內(nèi)部的view的可見性發(fā)生改變時,onGlobalLayout方法將被回調(diào),因此這是獲取view的寬高的一個
很好的時機。同樣,當(dāng)view樹的狀態(tài)改變時,onGlobalLayout會被調(diào)用多次。
代碼如下:
@Override protected void onStart() { super.onStart(); ViewTreeObserver observer = view.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { view.getViewTreeObserver().removeGolbalLayoutListener(this); int width = view.getMeasureWidth(); int height = view.getMeasureHeight(); } });}(4)view.measure(int widthMeasureSpec,int heightMeasureSpec)
通過手動對view進(jìn)行measure來得到view的寬高,這里要分情況處理,根據(jù)View的LayoutParams來分。
match_parent:
直接放棄,無法measure出具體寬高,構(gòu)造此種measureSpec需要知道parentSize,即父容器的剩余空間,而這個時候我們無法知道parentSize的大小,所以理論上不可能測量出View的大小。
dp/px:
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY); int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY); view.measure(widthMeasureSpec,heightMeasureSpec);wrap_content:
如下measure:
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1, View.MeasureSpec.AT_MOST); int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) -1 , View.MeasureSpec.AT_MOST); view.measuew(widthMeasureSpec,heightMeasureSpec);注意到(1<<30)-1,通過分析MeasureSpec的實現(xiàn)可以知道,view的尺寸使用30位二進(jìn)制表示,也就是說最大是30個1(2^30-1),也就是(1<<30)-1,在最大化模式下,我們用view理論上能支持最大值去構(gòu)造measureSpec是合理的.
新聞熱點
疑難解答