Los WebView son una herramienta de uso común para las aplicaciones móviles, y se utilizan ampliamente en diversas aplicaciones móviles. Una de las mayores ventajas de las aplicaciones híbridas es la posibilidad de desarrollar y mantener una única base de código para algunas funciones que pueden desplegarse en varias plataformas, como iOS y Android, sin necesidad de lanzar nuevas versiones de la aplicación. Sin embargo, los WebView tienen algunos inconvenientes. Uno de los principales es que pueden no funcionar tan bien como las aplicaciones nativas, especialmente en términos de velocidad de carga, animaciones y desplazamiento. Además, los WebView pueden tener limitaciones en cuanto al acceso a las características y funcionalidades del dispositivo, pueden no ser capaces de utilizar plenamente las capacidades del dispositivo, carecen de consistencia a través de diferentes versiones del sistema operativo, y pueden tener problemas cuando se utilizan junto con otros componentes nativos de interfaz de usuario. Hoy hablaremos de los retos relacionados con el desplazamiento anidado en Android que encontramos en nuestras aplicaciones, así como de las soluciones que implementamos.
Cómo hacer que funcione el desplazamiento anidado
Considere este sencillo ejemplo, totalmente nativo, de desplazamiento anidado que presenta un RecyclerView y una barra de herramientas colapsable. La barra de herramientas se contrae a medida que el RecyclerView se desplaza hacia abajo, y se expande cuando se alcanza el desplazamiento máximo hacia arriba. Funciona a la perfección ya que el RecyclerView permite el desplazamiento anidado.
Animación de desplazamiento cuando se utiliza un RecyclerView
Ahora queremos reemplazar el RecyclerView con contenido web. Para ello, sustituiremos el RecyclerView por un componente WebView y cargaremos contenido HTML plano en él. Aunque WebView es un elemento desplazable, no admite el desplazamiento anidado. Esto significa que podemos desplazar el contenido de la web, pero no afecta a la barra de herramientas. Incluso si activamos el desplazamiento anidado en la vista, el comportamiento sigue siendo el mismo.
Animación de desplazamiento incorrecta cuando se utiliza una vista web normal
Para resolver este problema, una solución común es envolver el componente WebView en un NestedScrollView, que manejará de manera eficaz los eventos de desplazamiento.
Animación de desplazamiento cuando se utiliza un WebView dentro de un NestedScrollView
Parece que nuestro objetivo se ha logrado y ahora el comportamiento de desplazamiento es correcto. Sin embargo, vamos a comprobar las alturas de desplazamiento de la ventana y del documento del WebView para asegurarnos de que todo funciona según lo previsto.
Altura de la ventana WebView cuando se usa dentro de NestedScrollView:
window.innerHeight
1705
document.documentElement.scrollHeight
1705
Mientras que en el ejemplo anterior:
window.innerHeight
665
document.documentElement.scrollHeight
1705
Como puedes ver, cuando se utiliza dentro de un NestedScrollView, el tamaño de la ventana del WebView aumenta hasta la altura del tamaño del contenido, cosa que no ocurría en el ejemplo anterior. Aunque hemos manejado con éxito el desplazamiento anidado, esto tiene algunas implicaciones significativas:
- Si el contenido de la página es largo, esto puede suponer penalizaciones de rendimiento, ya que se debe renderizar toda la página.
- En el caso de páginas de desplazamiento en las que se cargan continuamente nuevos contenidos a medida que el usuario se desplaza por la página, activará todas estas cargas automáticamente, lo que podría acabar en importantes problemas de rendimiento. Piensa, por ejemplo, en un feed de noticias "infinito".
- El contenido de la página basado en la altura de la ventana puede mostrarse incorrectamente. Piensa, por ejemplo, en los elementos fijos de pie de página, que se mostrarán siempre al final del contenido desplazable.
Si piensas utilizar el atributo android:fillViewport="true" en NestedScrollView, el tamaño de la ventana será correcto, pero no podrás realizar ningún desplazamiento.
Nuestra biblioteca WebView de desplazamiento anidado para Android
github.com/Telefonica/android-nested-scroll-webview es una biblioteca de fuente abierta desarrollada por nosotros. Proporciona un componente WebView con soporte de desplazamiento anidado, que puede utilizarse de forma similar al RecyclerView del primer ejemplo. La implementación implica una extensión de un WebView que incluye la lógica de intercepción de eventos táctiles de NestedScrollView, pero teniendo en cuenta el rango de desplazamiento del WebView. De este modo, el desplazamiento anidado es compatible directamente con el propio componente, incluidos los movimientos de arrastrar y soltar.
Animación de desplazamiento utilizando NestedScrollWebView
Altura de la ventana WebView utilizando NestedScrollWebView: :
window.innerHeight
665
document.documentElement.scrollHeight
1705
Además, y debido a este problema cuando se expande la barra de herramientas dentro del CoordinatorLayout, en lugar de redimensionar el espacio dejado por la barra de herramientas, el CoordinatorLayout empuja hacia abajo el contenido inferior. Esto puede ser un problema, por ejemplo, para las páginas en las que se muestra un elemento de pie de página fijo.
Animación de desplazamiento de NestedScrollWebView con pie de página fijo html
Se trata de una operación costosa en términos de rendimiento, ya que cualquier cambio de tamaño de la barra de herramientas provoca una modificación del tamaño de la WebView, por lo que está desactivada por defecto.
Limitaciones y mejoras conocidas
Nuestra biblioteca no resuelve todos los problemas relacionados con el desplazamiento anidado y WebViews en Android. Por ejemplo, como la implementación se basa en la interceptación de eventos táctiles
NestedScrollView, en los casos en los que haya elementos de contenido web que intercepten eventos de movimiento (como una vista de mapa o un carrusel horizontal), estos eventos de movimiento pueden interpretarse como eventos de desplazamiento para el desplazamiento anidado, provocando que la página se desplace verticalmente cuando no debería hacerlo. Estamos trabajando en una solución. Si tienes algún comentario o sugerencia, compártelo con nosotros a través de nuestro repositorio GitHub.
Agradecemos las aportaciones externas para seguir mejorando.
Gracias.