Con WindowInsetsCompat,
tu app puede consultar y controlar el teclado en pantalla (también llamado
IME) de manera similar a la
forma en que interactúa con las barras del sistema. Tu app también puede usar
WindowInsetsAnimationCompat
para crear transiciones sin interrupciones cuando se abre o se cierra el teclado en pantalla.
Requisitos previos
Antes de configurar el control y la animación para el teclado en pantalla, configura tu app para que se muestre de extremo a extremo. Esto le permite controlar los elementos insertados de la ventana del sistema, como las barras del sistema y el teclado en pantalla.
Verifica la visibilidad del software del teclado
Usa WindowInsets para verificar la visibilidad del teclado de software.
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;
Como alternativa, puedes usar
ViewCompat.setOnApplyWindowInsetsListener
para observar los cambios en la visibilidad del teclado en pantalla.
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; });
Sincroniza la animación con el teclado en pantalla
Cuando un usuario presiona un campo de entrada de texto, el teclado se desliza hacia su lugar desde la parte inferior de la pantalla, como se muestra en el siguiente ejemplo:
En el ejemplo etiquetado como "Unsynchronized" en la figura 2, se muestra el comportamiento predeterminado en Android 10 (nivel de API 29), en el que el campo de texto y el contenido de la app se ajustan en su lugar en lugar de sincronizarse con la animación del teclado, un comportamiento que puede ser visualmente discordante.
En Android 11 (nivel de API 30) y versiones posteriores, puedes usar
WindowInsetsAnimationCompatpara sincronizar la transición de la app con el teclado que se desliza hacia arriba y hacia abajo desde la parte inferior de la pantalla. Esto se ve más fluido, como se muestra en el ejemplo etiquetado como "Synchronized" en la figura 2.
Configura
WindowInsetsAnimationCompat.Callback
con la vista que se sincronizará con la animación del teclado.
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. });
Hay varios métodos para anular en WindowInsetsAnimationCompat.Callback,
es decir
onPrepare(),
onStart(),
onProgress(),
y
onEnd().
Comienza llamando a onPrepare() antes de cualquier cambio de diseño.
Se llama a onPrepare cuando se inicia una animación de elementos insertados y antes de que se vuelvan a diseñar las vistas debido a una animación. Puedes usarla para guardar el estado inicial, que en este caso es la coordenada inferior de la vista.
onPrepare() para
registrar el estado inicial.
En el siguiente fragmento, se muestra una llamada de muestra a 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(); }
Se llama a onStart cuando se inicia una animación de elementos insertados. Puedes usarla para establecer todas las propiedades de la vista en el estado final de los cambios de diseño. Si tienes una devolución de llamada OnApplyWindowInsetsListener establecida en cualquiera de las vistas, ya se llama en este punto. Este es un buen momento para guardar el estado final de las propiedades de la vista.
onStart() para registrar
el estado final.
En el siguiente fragmento, se muestra una llamada de muestra a 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; }
Se llama a onProgress cuando cambian los elementos insertados como parte de la ejecución de una animación, por lo que puedes anularla y recibir una notificación en cada fotograma durante la animación del teclado. Actualiza las propiedades de la vista para que se anime en sincronización con el teclado.
Todos los cambios de diseño se completan en este punto. Por ejemplo, si usas View.translationY para desplazar la vista, el valor disminuye gradualmente para cada llamada de este método y, finalmente, alcanza 0 a la posición de diseño original.
onProgress() para
sincronizar las animaciones.
En el siguiente fragmento, se muestra una llamada de muestra a 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; }
De manera opcional, puedes anular onEnd. Se llama a este método después de que finaliza la animación. Este es un buen momento para limpiar los cambios temporales.
Recursos adicionales
- WindowInsetsAnimation en GitHub.