解決在onCreate()過程中獲取View的width和Height爲0的4種方法

很經常當我們動態創建某些View時,需要通過獲取他們的width和height來確定別的view的佈局,但是在onCreate()獲取view的width和height會得到0.view.getWidth()view.getHeight()爲0的根本原因是控件還沒有完成繪製,你必須等待系統將繪製完View時,才能獲得。這種情況當你需要使用動態佈局(使用wrap_contentmatch_parent)就會出現。一般來講在Activity.onCreate(...)onResume()方法中都沒有辦法獲取到View的實際寬高。所以,我們必須用一種變通的方法,等到View繪製完成後去獲取width和Height。下面有一些可行的解決方案。

1、監聽Draw/Layout事件:ViewTreeObserver

ViewTreeObserver監聽很多不同的界面繪製事件。一般來說OnGlobalLayoutListener就是可以讓我們獲得到view的width和height的地方.下面onGlobalLayout內的代碼會在View完成Layout過程後調用。

複製代碼
 1 view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
 2         @Override
 3         public void onGlobalLayout() {
 4             mScrollView.post(new Runnable() {
 5                 public void run() {
 6                     view.getHeight(); //height is ready
 7                 }
 8             });
 9         }
10 });
複製代碼

但是要注意這個方法在每次有些view的Layout發生變化的時候被調用(比如某個View被設置爲Invisible),所以在得到你想要的寬高後,記得移除onGlobleLayoutListener:

在 SDK Lvl < 16時使用
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim) 

在 SDK Lvl >= 16時使用
public void removeOnGlobalLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)

2、將一個runnable添加到Layout隊列中:View.post()

這個解決方案是我最喜歡的,但是幾乎沒人知道有這個方法。簡單地說,只要用View.post()一個runnable就可以了。runnable對象中的方法會在View的measure、layout等事件後觸發,具體的參考Romain Guy

UI事件隊列會按順序處理事件。在setContentView()被調用後,事件隊列中會包含一個要求重新layout的message,所以任何你post到隊列中的東西都會在Layout發生變化後執行。

複製代碼
1 final View view=//smth;
2 ...
3 view.post(new Runnable() {
4             @Override
5             public void run() {
6                 view.getHeight(); //height is ready
7             }
8         });
複製代碼

這個方法比ViewTreeObserver好:
1、你的代碼只會執行一次,而且你不用在在每次執行後將Observer禁用,省心多了。
2、語法很簡單


參考:
http://stackoverflow.com/a/3602144/774398
http://stackoverflow.com/a/3948036/774398

 

3、重寫View的onLayout方法

這個方法只在某些場景中實用,比如當你所要執行的東西應該作爲他的內在邏輯被內聚、模塊化在view中,否者這個解決方案就顯得十分冗長和笨重。

複製代碼
1 view = new View(this) {
2     @Override
3     protected void onLayout(boolean changed, int l, int t, int r, int b) {
4         super.onLayout(changed, l, t, r, b);
5         view.getHeight(); //height is ready
6     }
7 };
複製代碼

需要注意的是onLayout方法會調用很多次,所以要考慮好在這個方法中要做什麼,或者在第一次執行後禁用掉你的代碼。

 

附加:獲取固定寬高

如果你要獲取的view的width和height是固定的,那麼你可以直接使用:

1 View.getMeasureWidth()
2 View.getMeasureHeight()

但是要注意,這兩個方法所獲取的width和height可能跟實際draw後的不一樣。官方文檔解釋了不同的原因

View的大小由width和height決定。一個View實際上同時有兩種width和height值。

第一種是measure width和measure height。他們定義了view想要在父View中佔用多少width和height(詳情見Layout)。measured height和width可以通過getMeasuredWidth() 和 getMeasuredHeight()獲得。

第二種是width和height,有時候也叫做drawing width和drawing height。這些值定義了view在屏幕上繪製和Layout完成後的實際大小。這些值有可能跟measure width和height不同。width和height可以通過getWidth()和getHeight獲得。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章