1. 程式人生 > >Activity正確獲取View寬高

Activity正確獲取View寬高

在View的measure完成後,一般可以通過getMeasureWidth/getMeasureWidth方法可以正確的獲取View的寬高,而在特殊情況下,可能需要多次measure才能確定最終的測量寬高,onMeasure無法獲取正確的寬高,但可以在onLayout方法中獲取測量寬高。

而在Activity生命週期方法中,是無法通過getMeasureWidth/getMeasureWidth獲取正確的測量寬高,是因為View的measure和Activity的生命週期方法不是同步執行的,因此無法保證Activity執行生命週期方法時View已經繪製完畢,如果沒有繪製完,寬高可能是0。可以通過以下四種方法解決這個問題:
1、Acvtivity/View#onWindowFocusChanged

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

需要注意的是,這個方法可能會被呼叫多次,例如onResume和onPause呼叫,均會呼叫這個方法。

2、view.post(runnable)

通過post可以將一個runnable投遞到訊息佇列的尾部,等待Looper呼叫次runnable時候,view已經初始化了。

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

3、ViewTreeObserver

view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        view.getViewTreeObserver().removeOnGlobalLayoutListener(this::onGlobalLayout);
        int width = view.getMeasuredWidth();
        int height = view.getMeasuredHeight();
    }
});

需要注意,伴隨著View樹的狀態改變,onGlobalLayout()會被呼叫多次。

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

通過手動對View進行measure來得到View的寬高,但需要根據不同情況來進行處理

  • match_parent

這個無法measure具體的寬高,是因為需要知道父容器的parentSize,但這個時候是無法獲取的。

  • 具體的數值
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);
  • wrap_content
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1 << 30) - 1, View.MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec, heightMeasureSpec);