有時(shí)需要在 onCreate() 方法中獲取某個(gè) View 組件的寬度和高度未桥,而直接調(diào)用 getWidth()肠骆、getHeight()肺蔚、getMeasuredWidth()加矛、getMeasuredHeight() 方法只會得到 0履婉。
實(shí)現(xiàn)方法
一、使用 View.measure 測量 View
該方法測量的寬度和高度可能與視圖繪制完成后的真實(shí)的寬度和高度不一致斟览。
int width = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
int height = View.MeasureSpec.makeMeasureSpec(0,
View.MeasureSpec.UNSPECIFIED);
view.measure(width, height);
view.getMeasuredWidth(); // 獲取寬度
view.getMeasuredHeight(); // 獲取高度
二毁腿、使用 ViewTreeObserver. OnPreDrawListener 監(jiān)聽事件
在視圖將要繪制時(shí)調(diào)用該監(jiān)聽事件,會被調(diào)用多次苛茂,因此獲取到視圖的寬度和高度后要移除該監(jiān)聽事件已烤。
view.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
view.getViewTreeObserver().removeOnPreDrawListener(this);
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
return true;
}
});
三、使用 ViewTreeObserver. OnGlobalLayoutListener 監(jiān)聽事件
在布局發(fā)生改變或者某個(gè)視圖的可視狀態(tài)發(fā)生改變時(shí)調(diào)用該事件妓羊,會被多次調(diào)用胯究,因此需要在獲取到視圖的寬度和高度后執(zhí)行 remove 方法移除該監(jiān)聽事件。
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
else {
view.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
}
});
四躁绸、重寫 View 的 onSizeChanged 方法
在視圖的大小發(fā)生改變時(shí)調(diào)用該方法裕循,會被多次調(diào)用,因此獲取到寬度和高度后需要考慮禁用掉代碼涨颜。
該實(shí)現(xiàn)方法需要繼承 View费韭,且多次被調(diào)用,不建議使用庭瑰。
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
}
五星持、重寫 View 的 onLayout 方法
該方法會被多次調(diào)用,獲取到寬度和高度后需要考慮禁用掉代碼弹灭。
該實(shí)現(xiàn)方法需要繼承 View督暂,且多次被調(diào)用揪垄,不建議使用。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
}
六逻翁、使用 View.OnLayoutChangeListener 監(jiān)聽事件(API >= 11)
在視圖的 layout 改變時(shí)調(diào)用該事件饥努,會被多次調(diào)用,因此需要在獲取到視圖的寬度和高度后執(zhí)行 remove 方法移除該監(jiān)聽事件八回。
view.addOnLayoutChangeListener(
new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int l, int t, int r, int b,
int oldL, int oldT, int oldR, int oldB) {
view.removeOnLayoutChangeListener(this);
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
}
});
七酷愧、使用 View.post() 方法
Runnable 對象中的方法會在 View 的 measure、layout 等事件完成后觸發(fā)缠诅。
UI 事件隊(duì)列會按順序處理事件溶浴,在 setContentView() 被調(diào)用后,事件隊(duì)列中會包含一個(gè)要求重新 layout 的 message管引,所以任何 post 到隊(duì)列中的 Runnable 對象都會在 Layout 發(fā)生變化后執(zhí)行士败。
該方法只會執(zhí)行一次,且邏輯簡單褥伴,建議使用谅将。
view.post(new Runnable() {
@Override
public void run() {
view.getWidth(); // 獲取寬度
view.getHeight(); // 獲取高度
}
});
以上為轉(zhuǎn)載內(nèi)容,個(gè)人學(xué)習(xí)收藏記錄重慢,原文地址
下面是自己的學(xué)習(xí)記錄饥臂。
首先第一個(gè)方法,以前用過伤锚,確實(shí)不準(zhǔn)確擅笔,猜測是應(yīng)該是因?yàn)閰?shù)沒有用好,因?yàn)閰?shù)只使用UNSPECIFIED未指定的測量方式屯援,一般像Wrap_Content猛们,才是該測量方式。
這里貼一個(gè)比較好用的狞洋, AndroidUtilCode收藏的方法弯淘。
public static int[] measureView(final View view) {
ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp == null) {
lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
}
int widthSpec = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
int lpHeight = lp.height;
int heightSpec;
if (lpHeight > 0) {
heightSpec = View.MeasureSpec.makeMeasureSpec(lpHeight, View.MeasureSpec.EXACTLY);
} else {
heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
}
view.measure(widthSpec, heightSpec);
return new int[]{view.getMeasuredWidth(), view.getMeasuredHeight()};
}
然后是自己在做自定義view的時(shí)候,需要在一次add代碼創(chuàng)建的view吉懊,使用上面的方法無法獲得寬高庐橙,因?yàn)槲沂褂玫氖荢crollView。像在自定義中借嗽,加載一次布局态鳖,應(yīng)該選中最后一個(gè)post的方法最為使用。
另外還用的多的恶导,應(yīng)該是第三種方式浆竭,一般在外部使用,比如需要等待Recyclerview繪制完成后進(jìn)行的操作。