1. 程式人生 > >Android獲取View的寬度和高度

Android獲取View的寬度和高度

前言:可能很多情況下,我們都會有在activity中獲取view 的尺寸大小(寬度和高度)的需求。面對這種情況,很多同學立馬反應:這麼簡單的問題,還用你說?你是不是傻。。然後立馬寫下getWidth()、getHeight()等方法,洋洋得意的就走了。然而事實就是這樣的嗎?實踐證明,我們這樣是獲取不到View的寬度和高度大小的,可能很多同學又會納悶了,這是為什麼呢?一直不都是這樣獲取大小的嘛!

疑問解答:實際情況下,View的measure過程和Activity的生命週期方法不是同步執行的,因此無法保證Activity在執行完某個生命週期方法時View已經測量完畢了,這種情況下,獲取到的尺寸大小就是0。因此,在很多情況下,我們正在為我們機智而得意時,事實卻讓我們大跌眼鏡,甚是尷尬。

解決方案:接下來我們介紹四種方式去正確的獲取View的尺寸大小。

onWindowFocusChanged方法中獲取:
onWindowFocusChanged方法執行時代表View已經初始化完畢了,寬度和高度已經測量完畢並且最終確認好了,這時我們可以放心的在這裡去獲取View 的寬度和高度。程式碼如下:

Activity的onWindowFocusChanged中獲取view的寬度和高度
 @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        super.onWindowFocusChanged(hasWindowFocus);
        if
(hasWindowFocus){ int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); } }

注意:雖然使用很方便,但在使用這個方法時需要特別注意:onWindowFocusChanged會執行多次,在Activity獲取焦點和失去焦點時都會被呼叫一次。即在onPause和onResume方法被執行時被反覆呼叫。

View.post(new Runnable())方法中獲取:
通過View.post方法把Runnable物件放到訊息佇列的末尾,當執行到這個runable方法的時候,View所有的初始化測量方法說明都已經執行完畢了。因此在這裡獲取的時候就是測量後的真實值。程式碼如下:

Activity通過mView.post方法獲取
   mView.post(new Runnable() {
            @Override
            public void run() {
                int width = mView.getMeasuredWidth();
                int height = mView.getMeasuredHeight();
            }
        });

通過ViewTreeObserver獲取:
當View樹的狀態發生改變或者View樹內部View的可見性發生改變的時候,onGlobalLayout將會被回撥。注意:伴隨著View樹的狀態改變,onGlobalLayout會被呼叫多次。實現如下:

在Activity生命週期方法中通過ViewTreeObserver獲取
 ViewTreeObserver observer = mView.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = mView.getMeasuredWidth();
                int height = mView.getMeasuredHeight();
            }
        });

手動呼叫View的measure方法後獲取
手動呼叫measure後,View會呼叫onMeasure方法對View發起測量,測量完後,就可以獲取測量後的寬度和高度了。但是要對LayoutParams的引數分情況處理才能得到具體的引數值:

View的LayoutParams引數為match_parent:這種情況下無法獲取到具體寬高值,因為當View的測量模式為match_parent時,寬高值是取父容器的剩餘空間大小作為它自己的寬高。而這時無法獲取到父容器的尺寸大小,因此獲取會失敗。

View的LayoutParams引數為具體值:

int width =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.EXACTLY);

int height =View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.EXACTLY);

view.measure(width,height);

int height=view.getMeasuredHeight(); 

int width=view.getMeasuredWidth();

View的LayoutParams引數為wrap_content:

int width =View.MeasureSpec.makeMeasureSpec((1<<30)-1,View.MeasureSpec.AT_MOST);

int height =View.MeasureSpec.makeMeasureSpec((1<<30)-1,View.MeasureSpec.AT_MOST);

view.measure(width,height);

int height=view.getMeasuredHeight(); 

int width=view.getMeasuredWidth();