Za pomocą WindowInsetsCompat
aplikacja może wysyłać zapytania do klawiatury ekranowej (zwanej też IME) i sterować nią w podobny sposób jak w przypadku interakcji z paskami systemowymi. Aplikacja może też używać
WindowInsetsAnimationCompat
do tworzenia płynnych przejść podczas otwierania lub zamykania klawiatury ekranowej.
Wymagania wstępne
Zanim skonfigurujesz sterowanie i animację klawiatury ekranowej, skonfiguruj aplikację tak, aby wyświetlała się na całej szerokości ekranu. Dzięki temu może obsługiwać wstawki okien systemowych, takie jak paski systemowe i klawiatura ekranowa.
Sprawdzanie widoczności oprogramowania klawiatury
Sprawdź widoczność klawiatury ekranowej za pomocą 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;
Możesz też użyć
ViewCompat.setOnApplyWindowInsetsListener
do obserwowania zmian widoczności klawiatury ekranowej.
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; });
Synchronizowanie animacji z klawiaturą ekranową
Gdy użytkownik kliknie pole do wpisywania tekstu, klawiatura wysunie się z dołu ekranu, jak pokazano w tym przykładzie:
Przykład oznaczony jako „Niesynchronizowany” na rysunku 2 pokazuje domyślne działanie w Androidzie 10 (poziom API 29), w którym pole tekstowe i treść aplikacji zatrzaskują się zamiast synchronizować z animacją klawiatury, co może być wizualnie nieprzyjemne.
W Androidzie 11 (poziom interfejsu API 30) i nowszym możesz użyć
WindowInsetsAnimationCompat
, aby zsynchronizować przejście aplikacji z wysuwaniem i chowanie klawiatury u dołu ekranu. Wygląda to płynniej, jak widać na przykładzie oznaczonym jako „Zsynchronizowane” na rysunku 2.
Skonfiguruj
WindowInsetsAnimationCompat.Callback
widok, który ma być synchronizowany z animacją klawiatury.
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. });
W WindowInsetsAnimationCompat.Callback
można zastąpić kilka metod, a mianowicie onPrepare()
, onStart()
, onProgress()
i onEnd()
.
Zacznij od wywołania onPrepare()
przed wprowadzeniem jakichkolwiek zmian w układzie.
onPrepare
jest wywoływana, gdy rozpoczyna się animacja wstawień i zanim widoki zostaną ponownie rozmieszczone z powodu animacji. Możesz go użyć do zapisania stanu początkowego, którym w tym przypadku jest dolny współrzędny widoku.

onPrepare()
, aby zarejestrować stan początkowy.
Poniższy fragment kodu pokazuje przykładowe wywołanie funkcji 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
jest wywoływana, gdy rozpoczyna się animacja wstawek. Możesz go użyć, aby ustawić wszystkie właściwości widoku na stan końcowy zmian układu. Jeśli masz wywołanie zwrotne OnApplyWindowInsetsListener
ustawione w dowolnym widoku, jest ono już wywoływane w tym momencie. To dobry moment, aby zapisać stan końcowy właściwości widoku.

onStart()
, aby nagrać stan końcowy.
Poniższy fragment kodu pokazuje przykładowe wywołanie funkcji 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
jest wywoływana, gdy wstawki zmieniają się w ramach animacji, więc możesz ją zastąpić i otrzymywać powiadomienia w każdej klatce podczas animacji klawiatury. Zaktualizuj właściwości widoku, aby animacja widoku była zsynchronizowana z klawiaturą.
Na tym etapie wszystkie zmiany układu są już gotowe. Jeśli na przykład użyjesz
View.translationY
, aby przesunąć widok, wartość będzie stopniowo zmniejszać się przy każdym wywołaniu tej metody i ostatecznie osiągnie 0
, czyli pierwotną pozycję układu.
onProgress()
, aby zsynchronizować animacje.
Poniższy fragment kodu pokazuje przykładowe wywołanie funkcji 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; }
Opcjonalnie możesz zastąpić wartość onEnd
. Ta metoda jest wywoływana po zakończeniu animacji. To dobry moment, aby usunąć wszelkie tymczasowe zmiany.
Dodatkowe materiały
- WindowInsetsAnimation w GitHubie.