Android獲取View的width和Height為0的解決方法

一、前言:

實(shí)際上在 onCreate、onStart、onResume中均無(wú)法正確得到某個(gè) View 的寬/高信息,這是因?yàn)?View 的 measure 過(guò)程和 Activity 的生命周期方法不是同步執(zhí)行的,因此無(wú)法保證 Activity 執(zhí)行了onCreate、onStart、onResume時(shí)某個(gè) View 已經(jīng)測(cè)量完畢。如果沒(méi)有測(cè)量完畢,那么獲得的寬/高就是 0。

當(dāng)我們動(dòng)態(tài)創(chuàng)建某些View時(shí),需要通過(guò)獲取他們的width和height來(lái)確定別的View的布局,但是在onCreate()獲取view的width和height會(huì)得到0。View.getWidth()和View.getHeight()為0的根本原因是控件還沒(méi)有完成繪制,你必須等待系統(tǒng)將繪制完View時(shí)才能獲得。

二、解決方案:

1. Activity/View#onWindowFocusChanged

onWindowFocusChanged這個(gè)方法的含義是:View 已經(jīng)初始化完畢,寬/高已經(jīng)準(zhǔn)備好了,這個(gè)時(shí)候去獲取寬/高時(shí)沒(méi)問(wèn)題的。需要注意的是,onWindowFocusChanged會(huì)被調(diào)用多次,當(dāng) Activity 的窗口得到焦點(diǎn)和失去焦點(diǎn)時(shí),均會(huì)被調(diào)用一次。如果頻繁地進(jìn)行 onResume 和 onPause,那么onWindowFocusChanged也會(huì)頻繁地調(diào)用。

@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if (hasFocus){
            int width = btn_weak.getMeasuredWidth();
            int height = btn_weak.getMeasuredHeight();
        }
    }

2. 監(jiān)聽(tīng)Draw/Layout事件:ViewTreeObserver

ViewTreeObserver監(jiān)聽(tīng)很多不同的界面繪制事件。一般來(lái)說(shuō)OnGlobalLayoutListener就是可以讓我們獲得到view的width和height的地方.下面onGlobalLayout內(nèi)的代碼會(huì)在View完成Layout過(guò)程后調(diào)用。
注意:伴隨著 View 樹(shù)的狀態(tài)改變等,onGlobalLayout會(huì)被調(diào)用多次。

ViewTreeObserver observer = view.getViewTreeObserver();
  observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
                btn_weak.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        int width = view.getWidth();
        int height = view.getHeight();
         }
        });

3. View.post(runnable)

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

UI事件隊(duì)列會(huì)按順序處理事件。在setContentView()被調(diào)用后,事件隊(duì)列中會(huì)包含一個(gè)要求重新layout的message,所以任何你post到隊(duì)列中的東西都會(huì)在Layout發(fā)生變化后執(zhí)行。

view.post(new Runnable() {
            @Override
            public void run() {
                int width = view.getWidth();
               int height = view.getHeight();
            }
        });

這個(gè)方法比ViewTreeObserver好:
1、你的代碼只會(huì)執(zhí)行一次,而且你不用在在每次執(zhí)行后將Observer禁用,省心多了。
2、語(yǔ)法很簡(jiǎn)單

4. 重寫(xiě)View的onLayout方法

這個(gè)方法只在某些場(chǎng)景中實(shí)用,比如當(dāng)你所要執(zhí)行的東西應(yīng)該作為他的內(nèi)在邏輯被內(nèi)聚、模塊化在view中,否者這個(gè)解決方案就顯得十分冗長(zhǎng)和笨重。

view = new View(this) {
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        view.getHeight(); //height is ready
    }
};

需要注意的是onLayout方法會(huì)調(diào)用很多次,所以要考慮好在這個(gè)方法中要做什么,或者在第一次執(zhí)行后禁用掉你的代碼。

5. 獲取View固定寬高

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

View.getMeasureWidth()
View.getMeasureHeight()

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

View的大小由width和height決定。一個(gè)View實(shí)際上同時(shí)有兩種width和height值。

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

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


參考鏈接:https://blog.csdn.net/lufengdie/article/details/48003631

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

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

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