@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iv = findViewById(R.id.iv);
System.out.println(iv.getWidth() + "------" + iv.getHeight()); // 輸出 0 0
}
onCreate 時視圖尚未經歷 measure -> layout -> draw 流程,寬高為 0。 只有佈局完成後才能獲取實際尺寸。
iv.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// 移除監聽,避免重複回調
iv.getViewTreeObserver().removeOnGlobalLayoutListener(this);
int w = iv.getWidth();
int h = iv.getHeight();
// 此處 w/h 已有效
}
});
iv.post(new Runnable() {
@Override
public void run() {
int w = iv.getWidth();
int h = iv.getHeight();
}
});
原理:將 Runnable 投遞到 UI 線程消息隊列末尾,待佈局遍歷完成後執行。
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
int w = iv.getWidth(); // 此時確保已佈局
}
}
| 方案 | 優點 | 缺點 |
|---|---|---|
| OnGlobalLayoutListener | 精確針對該 View,佈局完成即回調 | API 16+ 需用 removeOnGlobalLayoutListener |
| view.post | 代碼極簡,無版本兼容問題 | 非精確佈局完成,只是「稍後執行」 |
| onWindowFocusChanged | 適用多 View 統一獲取 | Activity 生命週期耦合,可能多次觸發 |
**onCreate 獲取寬高必為 0**。用 view.post() 最簡潔通用;精確控制用 OnGlobalLayoutListener。切記移除監聽防洩漏。