轉載請標明出處:1片楓葉的專欄
上1個github小項目中我們介紹了避免按鈕重復點擊的小框架,其實現的核心邏輯是重寫OnClickListener的onClick方法,添加避免重復點擊的邏輯,即為第2次點擊與第1次點擊的時間間隔添加闕值,若第2次點擊的時間間隔與第1次點擊的時間間隔小于闕值,則此次點擊無效,再次基礎上我們又封裝了點擊組件驗證網絡Listener,點擊組件驗證是不是登錄Listener等,具體可參考: github項目解析(7)–>避免按鈕重復點擊
本文中我將介紹1下android中Activity啟動時獲得組件寬高的3種方式。我們知道,有時候我們需要在Activity啟動的時候獲得某1組件的寬或是高用于動態的更改UI布局文件,但是這時候候我們直接通過getWidth和getHeight方法獲得是有問題的。為何這么說呢?這里我們可以下1個測試的例子來驗證1下:
問題:
/**
* 在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呢?我們在履行1遍呢?結果還是1樣的,兩個變量都是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呢?
緣由:
其實看過我之前寫過的
android源碼解析之(104)–>Activity啟動流程
android源碼解析(107)–>Activity布局加載流程
android源碼解析(108)–>Activity布局繪制流程
的同學應當對Activity的啟動流程和其布局加載繪制流程不陌生,Activity的啟動流程和Activity的布局文件加載繪制流程,其實沒有相干的關系的,其實兩個異步的加載流程,這樣我們在Activity的onCreate和onResume方法調用textView.getHeight或是textView.getWidth方法的時候,其組件并沒有履行完繪制流程,因此此時獲得到的組件的寬高都是默許的0,也就是沒法獲得組件的寬和高。
但是當我們將獲得組件寬高的方法卸載按鈕的點擊事件的時候,由于此時按鈕已顯示出來了,所以證明布局文件已加載繪制完成,這時候候點擊組件履行組件的獲得寬高方法,就可以正常的獲得到組件的寬和高了。
這也就是為何我們在onCreate和onResume方法中調用獲得組件寬高都是0,而在按鈕的點擊事件中獲得的時候正常的緣由了。
其他解決方案:
那末如果我們想在Activity的onCreate方法或是onReusme方法獲得組件的寬高怎樣辦呢?這里提供了以下的3種方式:
/**
* 重寫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對象獲得了焦點就會履行該語句,所以我們需要做1些邏輯判斷,讓它在我們需要打印獲得組件寬高的時候在履行。
/**
* 為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源碼解析(108)–>Activity布局繪制流程,這樣當我們計算完組件的寬高以后再履行獲得組件的寬高操作,自然能夠獲得到組件的寬度和高度。
/**
* 初始化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的布局加載繪制流程比較了解的同學應當知道,界面的顯示進程經過了:丈量位置,丈量大小,繪制,3個操作流程。而我們獲得組件的寬高就是獲得組件的大小,所以我們獲得的代碼必須要在組件履行完丈量大小以后,而不管是我們添加的onWindowFocusChanged方法,onPreDrawListener監聽,已onGlobalLayoutListener監聽其實都是在組件完成了丈量大小以后履行了,因此這時候候我們能夠正確的獲得到組件的寬和高。
總結:
該類庫主要是介紹了3種我們在Activity的啟動進程中獲得組件寬高的方式;
通太重寫onWidnowFocusChanged方法獲得組件寬高的方式,可能會回調幾次,這點需要我們注意;
項目保存地址:android-viewheight,歡迎star和follow
另外對github項目,開源項目解析感興趣的同學可以參考我的:
github項目解析(1)–>上傳android項目至github
github項目解析(2)–>將Android項目發布至JCenter代碼庫
github項目解析(3)–>android內存泄漏監測之leakcanary
github項目解析(4)–>動態更改TextView的字體大小
github項目解析(5)–>android日志框架
github項目解析(6)–>自定義實現ButterKnife框架
github項目解析(7)–>避免按鈕重復點擊