As best as I can tell, the only way to do this consistently with modern Android is with JavaScript:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
webView.evaluateJavascript("""
|var _fullScrollIntervalID = setInterval(function() {
| if (window.scrollY + window.innerHeight >= document.body.scrollHeight) {
| window.clearInterval(_fullScrollIntervalID);
| } else {
| window.scrollBy(0, 10);
| }
|}, 17);
""".trimMargin(), null)
}
}
The JavaScript APIs are aware of the size of the content.
This solution doesn't take into account changing viewport sizes, window.innerHeight
rounding errors, if document.body
isn't the scrolling element, etc.
As for a Java-based solution, it seems the Java APIs give the size of the view, rather than the length of the page:
- height
- contentHeight
- measuredHeight
- bottom
Maybe this changed when enableSlowWholeDocumentDraw
was introduced.
One Java API that is aware of the content length of the page is canScrollVertically
but it returns false for a short time after onPageFinished
is called. You could use some kind of delay to get around this. For example:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
ScrollRunnable().run()
}
}
// ...
val h = Handler()
inner class ScrollRunnable() : Runnable {
override fun run() {
// introduce some delay here!
if (webView.canScrollVertically(1)) {
webView.scrollBy(0, 10)
h.postDelayed(this, 17L)
}
}
}
I tested this on an Android API26 emulator and an Android TV API 22 emulator.