I have a NestedScrollView with a WebView inside. The WebView contains an HTML file with anchors, that are linked to the same file but difference places (imagine "menu" and "content" containers. when you click on a menu item the corresponding section in "content" should appear on the screen).
<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:id="@+id/svNested"
android:layout_height="match_parent"
tools:showIn="@layout/activity_single"
android:background="@color/colorPrimary">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.widget.NestedScrollView>
Loading data:
webView?.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null)
The problem is that these anchors doesn't work as expected.
I got anchors to work by calculating their position with Javascript inside the WebView and then programmatically scrolling the NestedScrollView by calling a custom URL and catching it with the WebViewClient. Here are some snippets (I only scroll vertically, but you can easily extend it to also work horizontally):
In your Activity or Fragment (where the NestedScrollView and WebView are referenced):
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
if(url.startsWith("scrollto")) {
val offset = url.replace("scrollto://", "");
val offsetInt = MapUtils.getDensityIndependentPixels(offset.toFloat(), requireContext()).toInt()
(webView.parent as NestedScrollView).scrollTo(0, offsetInt)
return true
}
return false
}
}
//We need this, because the measured pixels in the WebView don't use density of the screen
fun getDensityIndependentPixels(pixels: Float, context: Context): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
pixels,
context.resources.displayMetrics
)
}
Then in your Javascript (or <script>-Tag in the HTML):
function getOffset(el) {
const rect = el.getBoundingClientRect();
return {
top: rect.top + window.pageYOffset,
left: rect.left + window.pageXOffset
};
}
function makeItScroll(id) {
var element = document.getElementById(id)
var offsetTop = getOffset(element).top
window.location = "scrollto://"+offsetTop
}
And finally use it inside your HTML like this:
div you want to scroll to: <div id="here">...</div>
a to scroll there: <a href="javascript:makeItScroll('here');">...</a>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With