應用程式可以使用 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 中標示為「Un syncd」的示例顯示了 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
的呼叫範例:
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
的呼叫範例:
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
的呼叫範例:
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。