使用 WindowInsetsCompat
,應用程式可以查詢及控制螢幕小鍵盤 (也稱為 IME),與應用程式與系統資訊列互動的方式類似。應用程式也可以使用
WindowInsetsAnimationCompat
,在軟體鍵盤開啟或關閉時建立無縫轉場效果。
必要條件
設定軟體鍵盤的控制和動畫前,請先將應用程式設定為無邊框模式。這樣一來,系統就能處理系統視窗插邊,例如系統資訊列和螢幕小鍵盤。
檢查鍵盤軟體顯示設定
使用 WindowInsets
檢查軟體鍵盤是否顯示。
Kotlin
val insets = ViewCompat.getRootWindowInsets(view) ?: return val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()) val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
Java
WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(view); boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom;
或者,您也可以使用 ViewCompat.setOnApplyWindowInsetsListener
觀察軟體鍵盤顯示狀態的變化。
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -> val imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()) val imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom insets }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, insets) -> { boolean imeVisible = insets.isVisible(WindowInsetsCompat.Type.ime()); int imeHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom; return insets; });
將動畫與螢幕鍵盤同步
使用者輕觸文字輸入欄位時,鍵盤會從畫面底部滑入定位,如下列範例所示:
圖 2 中標示為「未同步」的範例顯示 Android 10 (API 級別 29) 的預設行為,也就是文字欄位和應用程式內容會直接就位,而不是與鍵盤的動畫同步,這種行為可能會造成視覺上的不協調感。
在 Android 11 (API 級別 30) 以上版本中,您可以使用
WindowInsetsAnimationCompat
,將應用程式的轉場效果與鍵盤從螢幕底部向上/向下滑動的動作同步。如圖 2 中標示為「已同步」的範例所示,這樣看起來會更平滑。
設定
WindowInsetsAnimationCompat.Callback
,與鍵盤動畫同步。
Kotlin
ViewCompat.setWindowInsetsAnimationCallback( view, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) { // Override methods. } )
Java
ViewCompat.setWindowInsetsAnimationCallback( view, new WindowInsetsAnimationCompat.Callback( WindowInsetsAnimationCompat.Callback.DISPATCH_MODE_STOP ) { // Override methods. });
您可以在 WindowInsetsAnimationCompat.Callback
中覆寫多種方法,包括 onPrepare()
、onStart()
、onProgress()
和 onEnd()
。請先呼叫 onPrepare()
,再進行任何版面配置變更。
當插邊動畫開始時,且在動畫導致檢視區塊重新配置之前,系統會呼叫 onPrepare
。您可以用來儲存開始狀態,在本例中為檢視區塊的底部座標。

onPrepare()
記錄開始狀態。以下程式碼片段顯示呼叫 onPrepare
的範例:
Kotlin
var startBottom = 0f override fun onPrepare( animation: WindowInsetsAnimationCompat ) { startBottom = view.bottom.toFloat() }
Java
float startBottom; @Override public void onPrepare( @NonNull WindowInsetsAnimationCompat animation ) { startBottom = view.getBottom(); }
當插邊動畫開始時,系統會呼叫 onStart
。您可以使用這項功能,將所有檢視區塊屬性設為版面配置變更的最終狀態。如果已為任何檢視區塊設定 OnApplyWindowInsetsListener
回呼,此時系統會呼叫該回呼。建議您現在儲存檢視區塊屬性的最終狀態。

onStart()
記錄結束狀態。以下程式碼片段顯示呼叫 onStart
的範例:
Kotlin
var endBottom = 0f override fun onStart( animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat ): WindowInsetsAnimationCompat.BoundsCompat { // Record the position of the view after the IME transition. endBottom = view.bottom.toFloat() return bounds }
Java
float endBottom; @NonNull @Override public WindowInsetsAnimationCompat.BoundsCompat onStart( @NonNull WindowInsetsAnimationCompat animation, @NonNull WindowInsetsAnimationCompat.BoundsCompat bounds ) { endBottom = view.getBottom(); return bounds; }
當插邊在動畫執行期間變更時,系統會呼叫 onProgress
,因此您可以覆寫該函式,並在鍵盤動畫期間的每個影格收到通知。更新檢視區塊屬性,讓檢視區塊與鍵盤同步顯示動畫。
此時所有版面配置變更都已完成。舉例來說,如果您使用 View.translationY
偏移檢視區塊,每次呼叫這個方法時,值都會逐漸減少,最終達到 0
,回到原始版面配置位置。
onProgress()
同步處理動畫。以下程式碼片段顯示呼叫 onProgress
的範例:
Kotlin
override fun onProgress( insets: WindowInsetsCompat, runningAnimations: MutableList<WindowInsetsAnimationCompat> ): WindowInsetsCompat { // Find an IME animation. val imeAnimation = runningAnimations.find { it.typeMask and WindowInsetsCompat.Type.ime() != 0 } ?: return insets // Offset the view based on the interpolated fraction of the IME animation. view.translationY = (startBottom - endBottom) * (1 - imeAnimation.interpolatedFraction) return insets }
Java
@NonNull @Override public WindowInsetsCompat onProgress( @NonNull WindowInsetsCompat insets, @NonNull List<WindowInsetsAnimationCompat> runningAnimations ) { // Find an IME animation. WindowInsetsAnimationCompat imeAnimation = null; for (WindowInsetsAnimationCompat animation : runningAnimations) { if ((animation.getTypeMask() & WindowInsetsCompat.Type.ime()) != 0) { imeAnimation = animation; break; } } if (imeAnimation != null) { // Offset the view based on the interpolated fraction of the IME animation. view.setTranslationY((startBottom - endBottom) * (1 - imeAnimation.getInterpolatedFraction())); } return insets; }
您也可以選擇覆寫 onEnd
。動畫結束後,系統會呼叫這個方法。現在是清除所有暫時變更的好時機。
其他資源
- GitHub 上的 WindowInsetsAnimation。