大家很多時候需要在Activity或者Fragment的onCreate()方法中獲取聲明的空間的高度或者寬度,進行位置移動或者其他操作,但是當調用 view.getHeight()
或者 view.getWidth()
獲取的竟然為0。。。
其實很容易理解,在onCreate()的時候,實際上控件只是聲明了,并沒有繪制完成,沒有attach到window上,所以導致獲取的高度和寬度為0
,那么該怎么解決呢?
三種方式
1、使用下面的post方式
view.post(new Runnable() {@Overridepublic void run() {int height = view.getHeight() ;int width = view.getWidth();}
});
原理:
-
View.post(Runnable) 內部會自動分兩種情況處理,當 View 還沒 attachedToWindow 時,會先將這些 Runnable 操作緩存下來;否則就直接通過 mAttachInfo.mHandler 將這些 Runnable 操作 post 到主線程的 MessageQueue 中等待執行。
-
如果 View.post(Runnable) 的 Runnable 操作被緩存下來了,那么這些操作將會在 dispatchAttachedToWindow() 被回調時,通過 mAttachInfo.mHandler.post() 發送到主線程的 MessageQueue 中等待執行。
想了解更多請去查看源碼。相信你可以更深層次的理解。
View.post() 中的操作執行時,View 的寬高已經計算完畢,所以可以在 Activity 的 onCreate() 里調用 View.post() 來解決獲取 View 寬高為0的問題
。
2、使用ViewTreeObserver的方式
ViewTreeObserver vto = view.getRabbit().getViewTreeObserver();
vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {public boolean onPreDraw() {if(vto.isAlive()){vto.removeOnDrawListener(this);}int height = view.getMeasuredHeight());return true;}
});
ViewTreeObserver 注冊一個觀察者來監聽視圖樹,當視圖樹的布局、視圖樹的焦點、視圖樹將要繪制、視圖樹滾動等發生改變時,ViewTreeObserver都會收到通知。所以 這個方法會調用很多次,如果要使用這種方法的話,要做好規避調用多次,記得移除監聽
;ViewTreeObserver不能被實例化,可以調用View.getViewTreeObserver()來獲得。
3、還有一種不太推薦
@Override
public void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);int height = view.getHeight()int width = view.getHeight();
}
這個函數的含義是:view已經初始化完畢了,寬/高已經準備好了,這個時候去獲取寬高是可以成功獲取的。需要注意的是 onWindowFocusChanged函數會被調用多次,當Activity的窗口得到焦點和失去焦點時均會被調用一次,如果頻繁地進行onResume和onPause,那么onWindowFocusChanged也會被頻繁地調用,不太適合處理一些復雜的業務邏輯
。