Distrito Telefónica. Innovation & Talent Hub

Back
Development

Nested scrolling with Android WebView

Webviews are a commonly used tool for mobile apps, and they are widely used in various mobile applications. One of the biggest benefits of hybrid apps is the ability to develop and maintain a single codebase for some features that can be deployed across multiple platforms, such as iOS and Android, without the need of releasing new app versions. Webviews, however, have some downsides. One of the main drawbacks is that they may not perform as well as native apps, especially in terms of loading speed, animations, and scrolling. Additionally, webviews may have limitations in terms of access to device features and functionality, may not be able to fully utilize the capabilities of the device, lack consistency across different versions of the operating system, and may have issues when used in conjunction with other native UI components. Today, we will discuss the challenges related to nested scrolling in Android that we encountered in our applications, as well as the solutions we implemented.

Trying to make nested scrolling to work

Consider this straightforward, fully native example of nested scrolling that features a RecyclerView and a collapsing toolbar. The toolbar collapses as the RecyclerView is scrolled down, and expands when the maximum scroll up is reached. It functions seamlessly as the RecyclerView supports nested scrolling.
Scroll view

Scroll view

Scrolling animation when using a RecyclerView

We now wish to replace the RecyclerView with web content. To do this, we will replace the RecyclerView with a WebView component and load plain HTML content onto it. While the WebView is a scrollable element, it does not support nested scrolling. This means that we can scroll the web content, but it does not affect the toolbar. Even if we enable nested scrolling on the view, the behavior remains the same.
Scroll view

Scroll view

Wrong scrolling animation when just using a regular webview

To resolve this issue, a common solution is to wrap the WebView component in a NestedScrollView, which will effectively handle scroll events.

Scroll view

Scroll view

Scrolling animation when using a WebView inside a NestedScrollView

It appears that our goal has been achieved and the scrolling behavior is now correct. However, we are going to check the WebView’s window and document scroll heights to ensure everything is working as intended. WebView window height when used inside a NestedScrollView:
window.innerHeight
1705
document.documentElement.scrollHeight
1705
  While in previous example:
window.innerHeight
665
document.documentElement.scrollHeight
1705
As you can see, when used inside a NestedScrollView, the WebView’s window size increases up to the content size height, which did not occur in the previous example. Although we have successfully handled nested scrolling, this has some significant implications:    

  • If page content is long, this may suppose performance penalties as whole page must be rendered.
  • In case of scrolling pages where new content is continuously loaded as user scrolls down the page, it will trigger all these loads automatically, this could end on important performance problems. Think about an “infinite” news feed for example.
  • Page content based on window height may be displayed wrongly. Think about on fixed footer elements for example, these will be always displayed at the end of the scrollable content.
If you plan to use the android:fillViewport=”true” attribute on NestedScrollView, window size will be correct, but you won’t be able to perform any scroll at all.

Our Android nested scroll Webview library

github.com/Telefonica/android-nested-scroll-webview is an open-source library developed by us. It provides a WebView component with nested scrolling support, which can be used in a similar way as the RecyclerView in the first example. The implementation involves an extension of a WebView that includes NestedScrollView touch event interception logic, but taking into account the WebView scroll range. This way, nested scrolling is directly supported by the component itself, including drag and fling movements.
Scroll view

Scroll view

Scrolling animation using NestedScrollWebView

WebView window height using NestedScrollWebView:
window.innerHeight
665
document.documentElement.scrollHeight
1705
Additionally, and because of this issue, when expanding toolbar inside the CoordinatorLayout, instead of resizing the space left by the toolbar, CoordinatorLayout pushes down the content below. This may be an issue for example for pages where a fixed footer element is displayed.
Scroll view

Scroll view

Scrolling animation of NestedScrollWebView with html fixed footer

So, in order to correctly resize the webview window on these expands, we provide a coordinatorBottomMatchingEnabled attribute that can be specified in the NestedScrollWebView component.
Scrolling animation of NestedScrollWebView with html fixed footer and coordinatorBottomMatching enabled.
This is an expensive operation in terms of performance, as any toolbar size change triggers a WebView size modification, so it is disabled by default.

Known Limitations & Improvements

Our library does not solve all issues related to nested scrolling and WebViews in Android. For example, as the implementation relies on NestedScrollView touch event interception, in cases where there are web content elements that intercept movement events (such as a map view or a horizontal carousel), these movement events may be interpreted as scrolling events for nested scrolling, causing the page to scroll vertically when it should not. We are currently working on a solution for this. If you have any feedback or suggestions, please share them with us through our GitHub repository. We appreciate external contributions to continue improving it. Thank you.