简体   繁体   中英

WebView nested scroll doesn't work in Android Jetpack Compose

WebView is not scrolling inside Compose. I need to put the WebView inside BottomSheet using the Compose. The problem that WebView is not scrolling even if we use eg NestedWebView , or NestedScrollWebView . If I put WebView inside NestedScrollView it still doesn't react on scroll.

BottomSheetScaffold(
        sheetContent = {
            AndroidView(factory = {
                NestedWebView(it).apply {
                        layoutParams = ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.MATCH_PARENT,
                            ViewGroup.LayoutParams.MATCH_PARENT
                        )
                        settings.domStorageEnabled = true
                        settings.javaScriptEnabled = true
                        settings.useWideViewPort = true
                        webViewClient = WebViewClient()
                        //loadUrl("https://contest.rippl.club/")
                        loadUrl("https://codeflarelimited.com")
                    }
                })

        }) {
    }

One of the workaround is to use verticalScroll and set the webview height as WRAP_CONTENT:

 val scrollState = rememberScrollState()
 AndroidView(modifier = Modifier.verticalScroll(scrollState), factory = {
            WebView(it).apply {
                     layoutParams = ViewGroup.LayoutParams(
                          ViewGroup.LayoutParams.MATCH_PARENT,
                          ViewGroup.LayoutParams.WRAP_CONTENT
                          ---//---

but there are a lot of sites that doesnt work with wrap_content for eg because of inner scrolling like this site https://contest.rippl.club/ . This site doesn't work with that workaround. If we set the webview height as screen height that it still doesnt work, because the verticalScroll works as ScrollView, so it will just scroll until this height.

I've also checked this doc https://developer.android.com/jetpack/compose/gestures#parent-compose-child-view , but nothing works for webview case.

You need to use a NestedScrollConnection object, and pass it to a nestedSCroll modifier on the outer view. Here's a basic example

There is the ease way to work around this issue. Ive got exact same case as you. All you need to do is implement pointerInput somehow like this:

AndroidView(
        modifier = Modifier
            .fillMaxHeight(0.9f)
            .pointerInput(Unit) {
                detectVerticalDragGestures { _, dragAmount ->
                    val initialDrag = currentVerticalDrag.value + dragAmount
                    val calculatedDrag = when {
                        initialDrag > 0 -> {
                            0
                        }
                        abs(initialDrag) > measuredHeight.value -> {
                            measuredHeight.value
                        }
                        else -> {
                            initialDrag.roundToInt()
                        }
                    }
                    currentVerticalDrag.value = calculatedDrag
                }
            },
        factory = {
            WebView(it).apply {
                settings.javaScriptEnabled = true
                addJavascriptInterface(jsInterface, "HTMLOUT")
                webViewClient = FaqWebViewClient(
                    onPageLoadingStart = {
                        isPageLoading.value = true
                    },
                    onPageLoadComplete = {
                        isPageLoading.value = false
                    }
                )
                loadUrl(url)
            }
        }, update = { webView ->
            webView.scrollTo(0, abs(currentVerticalDrag.value))
        }
    )

Here is a small sample code, which at least makes a WebView scrollable:

private class MyWebView(context: Context) : WebView(context) {
    val verticalScrollRange: Int get() = computeVerticalScrollRange() - height
}

@Composable
fun WebViewCompose(url: String, modifier: Modifier = Modifier, onCreated: (WebView) -> Unit = {}) {
    val context = LocalContext.current
    val webView: MyWebView = remember(context) {
        MyWebView(context).also(onCreated)
    }
    DisposableEffect(webView) {
        onDispose {
            webView.stopLoading()
            webView.destroy()
        }
    }
    val scrollabeState = rememberScrollableState { delta ->
        val scrollY = webView.scrollY
        val consume = (scrollY - delta).coerceIn(0f, webView.verticalScrollRange.toFloat())
        webView.scrollTo(0, consume.roundToInt())
        (scrollY - webView.scrollY).toFloat()
    }
    AndroidView(
        factory = { webView },
        modifier = modifier
            .scrollable(scrollabeState, Orientation.Vertical)
    ) { webView2 ->
        webView2.loadUrl(url)
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM