Dzięki WindowInsetsCompat,
Twoja aplikacja może wysyłać zapytania do klawiatury ekranowej (zwanej też
IME) i sterować nią podobnie jak
paskami systemowymi. Aplikacja może też używać
WindowInsetsAnimationCompat
, aby tworzyć płynne przejścia podczas otwierania i zamykania klawiatury ekranowej.
Wymagania wstępne
Zanim skonfigurujesz sterowanie klawiaturą ekranową i animację, skonfiguruj aplikację tak, aby wyświetlała się od krawędzi do krawędzi. Dzięki temu będzie mogła obsługiwać wcięcia okna systemowego, takie jak paski systemowe i klawiatura ekranowa.
Sprawdzanie widoczności klawiatury programowej
Aby sprawdzić widoczność klawiatury programowej
, użyj 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
aby obserwować zmiany 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 wprowadzania danych, klawiatura wysunie się z dołu ekranu, jak pokazano w tym przykładzie:
Przykład oznaczony jako „Niesynchronizowany” na rysunku 2 pokazuje działanie domyślne w Androidzie 10 (poziom API 29), w którym pole tekstowe i treść aplikacji zatrzaskują się na miejscu zamiast synchronizować się z animacją klawiatury. Może to być wizualnie nieprzyjemne.
W Androidzie 11 (poziom API 30) i nowszych wersjach możesz użyć
WindowInsetsAnimationCompat, aby zsynchronizować przejście aplikacji z wysuwaniem i chowaniem klawiatury z dołu ekranu. Wygląda to płynniej, jak pokazano w przykładzie oznaczonym jako „Zsynchronizowany” na rysunku 2.
Skonfiguruj
WindowInsetsAnimationCompat.Callback
z widokiem, który ma być zsynchronizowany 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,
m.in.
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 wcięć i zanim widoki zostaną ponownie ułożone z powodu animacji. Możesz jej użyć do zapisania stanu początkowego, którym w tym przypadku jest współrzędna dolna widoku.
onPrepare() do
rejestrowania stanu początkowego.
Ten fragment kodu pokazuje przykładowe wywołanie 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 wcięć. Możesz jej użyć do ustawienia wszystkich właściwości widoku na stan końcowy zmian układu. Jeśli masz ustawiony wywołanie zwrotne OnApplyWindowInsetsListener w którymkolwiek z widoków, zostanie ono wywołane w tym momencie. To dobry moment na zapisanie stanu końcowego właściwości widoku.
onStart() do rejestrowania
stanu końcowego.
Ten fragment kodu pokazuje przykładowe wywołanie 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 wcięcia zmieniają się w ramach animacji, więc możesz ją zastąpić i otrzymywać powiadomienia o każdej klatce podczas animacji klawiatury. Zaktualizuj właściwości widoku, aby animacja widoku była zsynchronizowana z klawiaturą.
W tym momencie wszystkie zmiany układu są zakończone. Jeśli na przykład używasz View.translationY do przesuwania widoku, wartość stopniowo maleje przy każdym wywołaniu tej metody i ostatecznie osiąga wartość 0 w pierwotnym położeniu układu.
onProgress() do
synchronizowania animacji.
Ten fragment kodu pokazuje przykładowe wywołanie 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ć onEnd. Ta metoda jest wywoływana po zakończeniu animacji. To dobry moment na usunięcie wszelkich tymczasowych zmian.
Dodatkowe materiały
- WindowInsetsAnimation na GitHubie.