前言
在Activity獲取控件寬高時,有時獲取的爲0,無法獲取正確的信息,原因是View的measure過程和Activity的生命週期不是同步的,也就是說在Activity走了onCreate、onStart、onResume週期後,並不一定View能測繪完成。
解決方式
- 在
onWindowFocusChanged
方法中做監聽
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus){
int width = txt.getMeasuredWidth();
int height = txt.getMeasuredHeight();
Log.e("測試","onWindowFocusChanged: "+width+"---"+height);
}
}
此方法,在Activity失去或者獲取到焦點時,會多次調用。
- 採用
post
方法
//txt是一個view
txt.post(new Runnable() {
@Override
public void run() {
int width = txt.getMeasuredWidth();
int height = txt.getMeasuredHeight();
Log.e("測試","post: "+width+"---"+height);
}
});
post
將一個Runnable
放到消息隊列中,運行在UI線程中,此Runnable所在的隊列,會在view被attached時,進行調用,所以此時,view已經初始化好。
ViewTreeObserver
方式
ViewTreeObserver observer = txt.getViewTreeObserver();
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
txt.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int width = txt.getMeasuredWidth();
int height = txt.getMeasuredHeight();
Log.e("測試","ViewTreeObserver: "+width+"---"+height);
}
});
當視圖樹的狀態發生改變或者視圖的可見性發生改變,onGlobalLayout
將會被回調,此監聽會多次回調,所以要及時註銷監聽。
- view.measure(int widthMeasureSpec, int heightMeasureSpec) 手動測量
private void measuWidthHeight(){
//具體值
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY);
//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);
txt.measure(widthMeasureSpec,heightMeasureSpec);
Log.e("測試","post: "+txt.getMeasuredWidth()+"---"+txt.getMeasuredHeight());
}
對於match_parent
來說,是無法進行測量的,因爲此時無法知道父容器的剩餘空間。
附錄
View的MesaureSpec創建規則表