Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> github項目解析(八)--)Activity啟動過程中獲取組件寬高的三種方式

github項目解析(八)--)Activity啟動過程中獲取組件寬高的三種方式

編輯:關於Android編程

上一個github小項目中我們介紹了防止按鈕重復點擊的小框架,其實現的核心邏輯是重寫OnClickListener的onClick方法,添加防止重復點擊的邏輯,即為第二次點擊與第一次點擊的時間間隔添加阙值,若第二次點擊的時間間隔與第一次點擊的時間間隔小於阙值,則此次點擊無效,再次基礎上我們又封裝了點擊組件驗證網絡Listener,點擊組件驗證是否登錄Listener等

本文中我將介紹一下android中Activity啟動時獲取組件寬高的三種方式。我們知道,有時候我們需要在Activity啟動的時候獲取某一組件的寬或者是高用於動態的更改UI布局文件,但是這時候我們直接通過getWidth和getHeight方法獲取是有問題的。為什麼這麼說呢?這裡我們可以下一個測試的例子來驗證一下:


問題:

在Activity的啟動流程中通過getWidht和getHeight方法獲取組件的寬度和高度
/**
 * 在onCreate方法中調用,用於獲取TextView的寬度和高度
 */
private void getTextHeightAndWidth() {
        // 我們定義的用於獲取寬度和高度的組件
        titleText = (TextView) findViewById(R.id.text_title);

        int height = titleText.getHeight();
        int width = titleText.getWidth();

        Log.i(TAG, "height:" + height + "  " + "width:" + width);
    }

這段代碼看似是正常沒有問題的,但是我們將調用的代碼寫在onCreate方法的時候,執行這段代碼之後,打印的結果:

06-26 20:12:15.356 19453-19453/uuch.com.android_viewheight I/MainActivity: height:0  width:0

咦?為什麼打印的height和width都是0呢?我們在執行一遍呢?結果還是一樣的,兩個變量都是0,難道這段代碼不能再onCreate方法中調用,那麼我們試試在onResume方法中調用呢?

只能說然並卵,打印的結果依然是:

06-26 20:52:13.986 19453-19453/uuch.com.android_viewheight I/MainActivity: height:0  width:0

好吧,問題已經出來了,看樣子我們是不能再onCreate方法或者是onResume方法中調用該方法獲取組件的寬高的,但是這是為什麼呢?平時我們都是通過這個方法來獲取組件的寬高的,並且也沒問題啊,比如我們將這個方法的調用邏輯寫在按鈕的點擊事件之內呢?我們再來試試。

/**
 * 這裡的button1是我們定義的Button組件,並且我們重寫了Button的點擊事件,在其中調用了獲取組件寬高的方法
 */
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getTextHeightAndWidth();
            }
        });

這樣敲完代碼之後,我們執行這段代碼,界面入下圖所示:
這裡寫圖片描述

那麼我們的打印結果呢?

06-26 20:57:08.188 22648-22648/uuch.com.android_viewheight I/MainActivity: height:57  width:225

恩?這時候我們發現其打印出了組件的寬和高,那麼為什麼我們在Activity的onCreate、onResume方法中打印的時候,輸出的組件寬高都是為0呢?


原因:

Activity的啟動流程和Activity的布局文件加載繪制流程,其實沒有相關的關系的,其實兩個異步的加載流程,這樣我們在Activity的onCreate和onResume方法調用textView.getHeight或者是textView.getWidth方法的時候,其組件並沒有執行完繪制流程,因此此時獲取到的組件的寬高都是默認的0,也就是無法獲取組件的寬和高。

但是當我們將獲取組件寬高的方法卸載按鈕的點擊事件的時候,由於此時按鈕已經顯示出來了,所以證明布局文件已經加載繪制完成,這時候點擊組件執行組件的獲取寬高方法,就能正常的獲取到組件的寬和高了。

這也就是為什麼我們在onCreate和onResume方法中調用獲取組件寬高都是0,而在按鈕的點擊事件中獲取的時候正常的原因了。


其他解決方案:

那麼如果我們想在Activity的onCreate方法或者是onReusme方法獲取組件的寬高怎麼辦呢?這裡提供了以下的三種方式:

重寫Activity的onWindowFocusChanged方法
/**
 * 重寫Acitivty的onWindowFocusChanged方法
 */ 
@Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        /**
         * 當hasFocus為true的時候,說明Activity的Window對象已經獲取焦點,進而Activity界面已經加載繪制完成
         */
        if (hasFocus) {
            int widht = titleText.getWidth();
            int height = titleText.getHeight();
            Log.i(TAG, "onWindowFocusChanged width:" + widht + "   "
                            + "  height:" + height;
        }
    }


說明:

這樣重寫onWindowFocusChanged方法,當獲取焦點的時候我們就可以通過getWidth和getHeight方法得到組件的寬和高了。但是這時候這個方法的邏輯可能會執行多次,也就是說只要我們的Activity的window對象獲取了焦點就會執行該語句,所以我們需要做一些邏輯判斷,讓它在我們需要打印獲取組件寬高的時候在執行。

為組件添加OnGlobalLayoutListener事件監聽
/**
 * 為Activity的布局文件添加OnGlobalLayoutListener事件監聽,當回調到onGlobalLayout方法的時候我們通過getMeasureHeight和getMeasuredWidth方法可以獲取到組件的寬和高
 */
private void initOnLayoutListener() {
        final ViewTreeObserver viewTreeObserver = this.getWindow().getDecorView().getViewTreeObserver();
        viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                Log.i(TAG, "開始執行onGlobalLayout().........");
                int height = titleText.getMeasuredHeight();
                int width = titleText.getMeasuredWidth();

                Log.i(TAG, "height:" + height + "   width:" + width);
            }
        });
    }

說明:

需要說明的是這裡的onGlobalLayout方法會在Activity的組件執行完onLayout方法之後執行,這裡的onLayout方法主要用於計算組件的寬高操作,具體可參考:android源碼解析(十八)–>Activity布局繪制流程,這樣當我們計算完組件的寬高之後再執行獲取組件的寬高操作,自然能夠獲取到組件的寬度和高度。

為組件添加OnPreDrawListener事件監聽
/**
     * 初始化viewTreeObserver事件監聽,重寫OnPreDrawListener獲取組件高度
     */
    private void initOnPreDrawListener() {
        final ViewTreeObserver viewTreeObserver = this.getWindow().getDecorView().getViewTreeObserver();
        viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                Log.i(TAG, "開始執行onPreDraw().........");
                int height = titleText.getMeasuredHeight();
                int width = titleText.getMeasuredWidth();

                Log.i(TAG, "height:" + height + "   width:" + width);
                return true;
            }
        });
    }

說明:

需要說明的是這裡的onPreDraw方法會在Activity的組件執行onDraw方法之前執行,熟悉我們Activity組件加載繪制流程的同學應該知道,這裡的onDraw方法主要用於執行真正的繪制組件操作,而這時候我們已經計算出來了組件的位置,寬高等操作,這樣之後再執行獲取組件的寬高操作,自然能夠獲取到組件的寬度和高度。


其他說明:
需要說明的是如果對Acitivty的布局加載繪制流程比較了解的同學應該知道,界面的顯示過程經過了:測量位置,測量大小,繪制,三個操作流程。而我們獲取組件的寬高就是獲取組件的大小,所以我們獲取的代碼必須要在組件執行完測量大小之後,而無論是我們添加的onWindowFocusChanged方法,onPreDrawListener監聽,已經onGlobalLayoutListener監聽其實都是在組件完成了測量大小之後執行了,因此這時候我們能夠正確的獲取到組件的寬和高。


總結:

該類庫主要是介紹了三種我們在Activity的啟動過程中獲取組件寬高的方式;

通過重寫onWidnowFocusChanged方法獲取組件寬高的方式,可能會回調幾次,這點需要我們注意;

項目保存地址:android-viewheight,歡迎star和follow

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved