I have strange behaviour of one of my screens when...
# compose-android
e
I have strange behaviour of one of my screens when I added a WebView - it for some reason has wrong background while the webpage is loading. Why may it happen? Can WebView have wrong position during loading?
no_webview.mp4,with_webview.mp4
This are 2 recordings without and with WebView.
Copy code
@Composable
fun LegalDocumentScreen(
    modifier: Modifier = Modifier,
    documentUrl: String,
    screenTitle: String,
    onBackClicked: () -> Unit
) {
    BaseTitledScreen(
        modifier = modifier,
        screenTitle = screenTitle,
        showBackButton = true,
        showExitButton = false,
        onBackClicked = onBackClicked
    ) {
        var isLoading by remember { mutableStateOf(true) }

        Box(
            modifier = Modifier
                .fillMaxSize()
                .windowInsetsPadding(WindowInsets.safeContent)

        ) {
            WebViewWidget(
                modifier = Modifier.fillMaxSize(),
                url = "<https://www.jetbrains.com/>"
            ) {
                isLoading = false
            }

            if (isLoading) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .background(Colors.ScreenBackgroundColor),
                    contentAlignment = Alignment.Center
                ) {
                    LoadingAnimation()
                }
            }
        }
    }
}
This is the source code of this screen. When I comment the WebView widget I don’t see any problems. It looks like the WebView has wrong position during loading.
Copy code
@SuppressLint("SetJavaScriptEnabled")
@Composable
actual fun WebViewWidget(
    modifier: Modifier,
    url: String,
    onScrolledToTheEnd: (() -> Unit)?,
    onLoadingFinished: (() -> Unit)?,
) {
    AndroidView(
        modifier = modifier,
        factory = { context ->
            AppCompatWebView(context).apply {
                settings.javaScriptEnabled = true
                webViewClient = TagBeamWebViewClient(
                    onScrolledToTheEnd = onScrolledToTheEnd,
                    onLoadingFinished = onLoadingFinished
                )

                settings.loadWithOverviewMode = true
                settings.useWideViewPort = true
                settings.setSupportZoom(true)

                setOnOverScrolledListener(object : AppCompatWebView.OnOverScrolledListener {
                    override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
                        if (clampedY && scrollY != 0) {
                            onScrolledToTheEnd?.invoke()
                        }
                    }
                })
            }
        },
        update = { webView ->
            webView.loadUrl(url)
        }
    )
}
This is the WebViewWidget composable
t
You should maybe hide the webview until everything is loaded and rendered. There are special callback functions for this i think in the AppCompatWebView
e
I would like to understand how does it work. Why the WebView occupies more space than it’s parent Box?
j
We had a similar issue and worked around it with:
Copy code
setBackgroundColor(Color.Transparent.toColorInt())
t
Oh i thought your problem is the flickering white background of the webview.
e
@Jonas Did you set the transparent background in the WebView itself?
j
Yes, in
Copy code
WebView(context).apply {
e
I just tried it and still see the white blinking on top of the screen
It helped a bit, but didn’t resolve the issue completely.
j
I also see a tiny flickering in our app but as most of it is white on white it is not really noticeable. Hmm. Would also be interested into a proper solution.
j
The main problem is that WebView in Android is AbsoluteLayout and using measurements too late kind a. I think if you wrap WebView in a FrameLayout and adding layout params with weight 1f and height = 0 or something like that should work. Then having another container that webview always fill up and Compose knowing about it. It becomes a lot more complex if website in webview is not fill window however 😛
e
@Timo Drick I also tried to make WebView invisible while loading. It helps even a bit more. But it still produces quick white blink when the WebView is made visible back.
@Joel Denke I will try it, thanks
j
The height from the white surface I think is the initial height Compose gets because the Webview implementation sucks to be honest. And also depending if finishedLoading, what content measurement the website doing with javascript and window objects, and combined with a lot of other params to get the proper state when it actually completes, including measured content and all from CSS, HTML and all that magic 😛
Also there is a couple of nice things in this library for Android: https://developer.android.com/jetpack/androidx/releases/webkit
Accompanist webview is deprecated I know, but check source code here how they solved some of this painful headache of webviews: https://github.com/google/accompanist/blob/main/web/src/main/java/com/google/accompanist/web/WebView.kt
thank you color 1
Also be aware if your WebView container have to be nested scrollable, you have another headache of need to wrap inside NestedScrollView + FrameLayout with fillViewPort combined with some magic attributes to make it work 😛
c
I guess the flickering is from the website itself. Until css is loaded and applied you see the white background. You can set a dark theme in the <head> of the website.
🔥 1
e
@Joel Denke It looks like the trick with FrameLayout works! It is now blinking only inside the parent box! 😂
🤣 1
j
Should be possible to set the webview rendering background to be transparent as well I think. As long as the website itself not setting some odd background 🙂
331 Views