在 onCreate、onStart、onResume 中直接呼叫 view.getWidth()/getHeight() 回傳 0,因視圖尚未經歷 Measure → Layout → Draw 三階段,尺寸尚未計算完成。正解為使用 ViewTreeObserver.OnGlobalLayoutListener 監聽佈局完成事件。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TableLayout table = findViewById(R.id.board);
int w = table.getWidth(); // 0
int h = table.getHeight(); // 0
}
final TableLayout table = findViewById(R.id.board);
ViewTreeObserver vto = table.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
// 此時寬高已計算完成
int width = table.getWidth();
int height = table.getHeight();
Log.d("Size", "Table: " + width + "x" + height);
// 重要:移除監聽器避免重複觸發與記憶體洩漏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
table.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
table.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
// 執行需要尺寸的邏輯...
}
});
| 方案 | 觸發時機 | 優點 | 缺點 |
|---|---|---|---|
| OnGlobalLayoutListener | 佈局完成、尺寸確定 | 最準確、通用 | 需記得移除監聽器 |
| view.post(Runnable) | 下一幀 UI 執行緒 | 代碼簡單 | 不保證佈局已完成(極簡單佈局通常夠) |
| onWindowFocusChanged | 視窗獲得焦點 | 確保可見 | 可能觸發多次、非專門為尺寸 |
| doOnLayout / doOnNextLayout (Kotlin Extensions) | 佈局完成 | 語法簡潔、自動移除 | 需引入 ktx 依賴 |
// build.gradle: implementation "androidx.core:core-ktx:1.12.0"
table.doOnLayout { view ->
val width = view.width
val height = view.height
// 尺寸就緒,執行邏輯
}
TextView 行數、截斷位置View 依賴尺寸初始化繪圖參數RecyclerView、ViewPager 子項尺寸在 Adapter 綁定後才確定,需在 onBindViewHolder 或 OnGlobalLayoutListener 中處理。viewLifecycleOwner 綁定生命週期,避免洩漏。理解 Android 視圖繪製管線,善用 ViewTreeObserver,即能準確獲取任意視圖的實際尺寸。