在 onCreate 中直接調用 textView.getLineCount() 返回 0,因佈局尚未完成測量。
TextView tv = findViewById(R.id.tv1);
tv.setText("abcd\nhello\nworld123\n333333");
// 關鍵:post 到 UI 執行緒隊列尾部,佈局完成後執行
tv.post(() -> {
int lineCount = tv.getLineCount(); // 正確返回 4
Toast.makeText(this, "行數: " + lineCount, Toast.LENGTH_LONG).show();
});
View.post(Runnable) 將任務加入 ViewRootImpl 的消息隊列measure -> layout -> draw 流程結束,UI 執行緒處理該消息時,TextView 已完成行佈局getLineCount() 依賴 Layout 對象,僅在測量後可用| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
view.post() | 簡單、無洩漏、生命周期安全 | 延遲執行、非即時 | 大多數獲取尺寸/行數場景 |
ViewTreeObserver.OnGlobalLayoutListener | 可多次觸發、精確控制 | 需手動移除監聽、易洩漏 | 需監聽佈局變化、動畫前準備 |
doOnPreDraw (Kotlin 扩展) | 語法簡潔、自動移除 | 需 Kotlin/依賴 | Kotlin 專案首選 |
| 預估計算 | 即時、無延遲 | 不準確 (字體、間距、換行符影響) | 佈局前預留空間、佔位圖 |
// 使用 StaticLayout 離線測量 (適用於佈局前預估)
Paint paint = new Paint();
paint.setTextSize(tv.getTextSize());
paint.setTypeface(tv.getTypeface());
StaticLayout layout = StaticLayout.Builder.obtain(
tv.getText(), 0, tv.getText().length(), paint, tv.getWidth())
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
.setLineSpacing(tv.getLineSpacingExtra(), tv.getLineSpacingMultiplier())
.setIncludePad(tv.getIncludeFontPadding())
.setBreakStrategy(tv.getBreakStrategy())
.setHyphenationFrequency(tv.getHyphenationFrequency())
.build();
int lineCount = layout.getLineCount(); // 即時可用,無需佈局完成
onCreate 直接調用 getLineCount() → 返回 0onWindowFocusChanged 中調用 → 可行但生命周期較晚,且多次觸發text.split("\n").length 計算 → 忽略自動換行、寬度限制view.post(() -> { ... }) → 標準、安全、推薦