View工作原理 -- 工作過程 -- measure(3)

獲取View的寬/高

在Activity的onCreate、onStart、onResume中均無法正確得到某個View的寬/高信息,這是因為View的measure過程和Activity的生命周期方法不是同步執(zhí)行的,因此無法保證Activity執(zhí)行了onCreate、onStart、onResume時某個View已經(jīng)測量完畢了,如果View還沒有測量完畢,那么獲得的寬/高就是0。可以通過以下幾種方法獲取。

一、Activity/View#onWindowFocusChanged

onWindowFocusChanged方法的含義是:View已經(jīng)初始化完畢,寬/高已經(jīng)準(zhǔn)備好了,這個時候去獲取寬/高是沒問題的。需要注意的是,當(dāng)Activity的窗口得到焦點和失去焦點時均會被調(diào)用一次。

pubic void onWinowFocusChanged(boolean hasFocus) {
    super.onWinowFocusChanged(hasFocus);
    if(hasFocus) {
        int widht = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
    }
}

二、view.post(runnable)

通過post可以將runnable投遞到消息隊列的尾部,然后等待Looper調(diào)用此runnable的時候,View也已經(jīng)初始化好了。

protected void onStart() {
    super.onStart();
    view.post(new Runnable() {
        @Override
        public void run() {
            int width = view.getMeasuredWidth();
            int height = view.getMeasureHeight();
        }
    });
}

三、ViewTreeObserver

使用ViewTreeObserver的眾多回調(diào)可以完成這個功能,比如使用OnGlobalLayoutListener接口,當(dāng)View樹的狀態(tài)發(fā)生改變或者View樹內(nèi)部的View的可見性發(fā)生改變時,onGlobalLayout方法將被回調(diào)。需要注意的是,伴隨著View樹的狀態(tài)改變等,onGlobalLayout方法會被回調(diào)多次。

protected void onStart() {
    super.onStart();
    ViewTreeObserver observer = view.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @SuppressWarnings("deprecation")
        @Override
        public void onGlobalLayout() {
            view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
            int width = view.getMeasuredWidth();
            int height = view.getMeasuredHeight();
        }
    });
}

四、view.measure(int widthMeasureSpec, int heightMeasureSpec)

通過手動對View進行measure來得到View的寬/高。這種情況比較復(fù)雜,需要分情況處理,根據(jù)View的LayoutParams來分:
1.match_parent
無法measure出具體的寬/高。原因很簡單,根據(jù)View的measure過程,構(gòu)造此種MeasureSpec需要知道parentSize,即父容器的剩余空間,而這個時候我們無法知道parentSize,所以理論上不可能測量出View的大小。
2.固定大小
比如寬/高都是100px,代碼如下:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);

3.wrap_content
代碼如下:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec, heightMeasureSpec);

在最大化模式下,用View理論上能支持的最大值去構(gòu)造MeasureSpec是合理的。
例子:

//布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_layout"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="100px">

    <TextView
        android:id="@+id/main_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello, Android!"/>

    <Button
        android:id="@+id/main_btn"
        android:layout_width="200px"
        android:layout_height="wrap_content"
        android:layout_marginTop="100px"
        android:gravity="center"
        android:textAllCaps="false"
        android:text="Click"/>
</LinearLayout>

//代碼
private void testMeasureSpec() {
    int widthMeasureSpec,heightMeasureSpec;
    Logger.d("main_btn原始測量尺寸, width: " + mMainBtn.getMeasuredWidth() + ", height: " + mMainBtn.getMeasuredHeight());
    //寬度設(shè)置SpecMode為EXACTLY,SpecSize為400
    widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(400, View.MeasureSpec.EXACTLY);
    heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
    mMainBtn.measure(widthMeasureSpec, heightMeasureSpec);
    Logger.d("寬度設(shè)置SpecMode為 EXACTLY,SpecSize為 400");
    Logger.d("main_btn測量尺寸, width: " + mMainBtn.getMeasuredWidth() + ", height: " + mMainBtn.getMeasuredHeight());
    Logger.d("main_btn實際尺寸, width: " + mMainBtn.getWidth() + ", height: " + mMainBtn.getHeight());

    //寬度設(shè)置SpecMode為AT_MOST,SpecSize為(1 << 30) - 1
    widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
    heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
    mMainBtn.measure(widthMeasureSpec, heightMeasureSpec);
    Logger.d("寬度設(shè)置SpecMode為 AT_MOST,SpecSize為 (1 << 30) - 1");
    Logger.d("main_btn測量尺寸, width: " + mMainBtn.getMeasuredWidth() + ", height: " + mMainBtn.getMeasuredHeight());
    Logger.d("main_btn實際尺寸, width: " + mMainBtn.getWidth() + ", height: " + mMainBtn.getHeight());

    //寬度設(shè)置SpecMode為UNSPECIFIED,SpecSize為0
    widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
    heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
    mMainBtn.measure(widthMeasureSpec, heightMeasureSpec);
    Logger.d("寬度設(shè)置SpecMode為 UNSPECIFIED,SpecSize為 0");
    Logger.d("main_btn測量尺寸, width: " + mMainBtn.getMeasuredWidth() + ", height: " + mMainBtn.getMeasuredHeight());
    Logger.d("main_btn實際尺寸, width: " + mMainBtn.getWidth() + ", height: " + mMainBtn.getHeight());
}

//log
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:62)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn原始測量尺寸, width: 200, height: 96
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:67)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ 寬度設(shè)置SpecMode為 EXACTLY,SpecSize為 400
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:68)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn測量尺寸, width: 400, height: 96
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:69)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn實際尺寸, width: 200, height: 96
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:75)
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ 寬度設(shè)置SpecMode為 AT_MOST,SpecSize為 (1 << 30) - 1
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.243 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:76)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn測量尺寸, width: 176, height: 96
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:77)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn實際尺寸, width: 200, height: 96
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:83)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ 寬度設(shè)置SpecMode為 UNSPECIFIED,SpecSize為 0
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:84)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn測量尺寸, width: 176, height: 96
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╔════════════════════════════════════════════════════════════════════════════════════════
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ Thread: main
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ MainActivity.onWindowFocusChanged  (MainActivity.java:93)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║    MainActivity.testMeasureSpec  (MainActivity.java:85)
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╟────────────────────────────────────────────────────────────────────────────────────────
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ║ main_btn實際尺寸, width: 200, height: 96
03-25 12:58:55.253 15885-15885/com.tomorrow.androidtest2 D/zwm: ╚════════════════════════════════════════════════════════════════════════════════════════

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容