Dzięki WindowInsetsCompat
aplikacja może wysyłać zapytania do klawiatury ekranowej (zwaną też IME) i sterować nią w podobny sposób, podobnie jak w przypadku interakcji z paskami systemowymi. Aplikacja może też używać WindowInsetsAnimationCompat
, aby płynnie przechodzić między klawiaturami po otwarciu lub zamknięciu klawiatury programowej.
Wymagania wstępne
Zanim skonfigurujesz elementy sterujące i animacje na klawiaturze programowej, skonfiguruj aplikację tak, by wyświetlała od krawędzi do krawędzi. Dzięki temu może on obsługiwać ustawienia okien systemowych, takie jak paski systemowe i klawiatura ekranowa.
Sprawdź widoczność oprogramowania klawiatury
Użyj WindowInsets
, aby sprawdzić widoczność klawiatury programowej.
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ć narzędzia ViewCompat.setOnApplyWindowInsetsListener
, aby obserwować zmiany w widoczności klawiatury programowej.
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; });
Synchronizuj animacje za pomocą klawiatury programowej
Użytkownik klikający pole wprowadzania tekstu powoduje wysunięcie klawiatury z dołu ekranu na miejsce, jak pokazano w tym przykładzie:
Przykład oznaczony jako „Niezsynchronizowane” na ilustracji 2 pokazuje domyślne zachowanie w Androidzie 10 (poziom interfejsu API 29), w którym pole tekstowe i zawartość aplikacji wsuwają się na miejsce, zamiast synchronizować się z animacją klawiatury. Działanie, które może wprawiać w dezorientację.
Na Androidzie 11 (poziom interfejsu API 30) i nowszych możesz używać
WindowInsetsAnimationCompat
do synchronizowania przejścia w aplikacji, gdy klawiatura przesuwająca się w górę i w dół od dołu ekranu. Wygląda to płynniej, jak widać w przykładzie oznaczonym jako „Zsynchronizowane” na rys. 2.
Skonfiguruj widok danych WindowInsetsAnimationCompat.Callback
tak, aby 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. });
Istnieje kilka metod zastąpienia w WindowInsetsAnimationCompat.Callback
: onPrepare()
, onStart()
, onProgress()
i onEnd()
.
Zacznij od wywołania onPrepare()
, zanim cokolwiek zmieni się układ.
Funkcja onPrepare
jest wywoływana, gdy rozpoczyna się animacja z wgłębieniami i przed ponownym nałożeniem widoków z powodu animacji. Możesz jej użyć do zapisania stanu początkowego,
który w tym przypadku jest dolną współrzędną widoku.
Ten 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(); }
Funkcja onStart
jest wywoływana, gdy rozpoczyna się animacja wstawienia. Możesz go użyć, by we wszystkich właściwościach widoku przejść do stanu końcowego po zmianie układu. Jeśli masz wywołanie zwrotne OnApplyWindowInsetsListener
ustawione na dowolny z widoków, jest ono już w tym momencie wywoływane. To dobry moment na zapisanie stanu końcowego właściwości widoku.
Ten 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; }
Funkcja onProgress
jest wywoływana, gdy wstawki zmieniają się w trakcie odtwarzania animacji, więc można ją zastąpić i otrzymywać powiadomienia o każdej klatce podczas animacji klawiatury. Zaktualizuj właściwości widoku, aby jego animacja była synchronizowana z klawiaturą.
Na tym etapie wszystkie zmiany układu zostały zakończone. Jeśli np. użyjesz funkcji View.translationY
, aby przesunąć widok, wartość ta będzie stopniowo zmniejszać się przy każdym wywołaniu tej metody, aż do osiągnięcia pozycji 0
względem pierwotnego układu.
Ten 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ć ustawienie onEnd
. Metoda ta jest wywoływana
po zakończeniu animacji. To dobry moment na wyczyszczenie wszelkich tymczasowych zmian.
Dodatkowe materiały
- WindowInsetsAnimation w GitHubie.