google / accompanist

A collection of extension libraries for Jetpack Compose
https://google.github.io/accompanist
Apache License 2.0
7.43k stars 598 forks source link

[WebView] Support saving and loading state and custom layout params #1557

Closed bentrengrove closed 1 year ago

bentrengrove commented 1 year ago

Enables the ability to save and restore WebView state when leaving and reentering composition.

In order to restore state you must use the new rememberSaveableWebViewState() API that doesn't take an initial URL. Then you can check if any view state exists before loading a URL in the WebView. This also allows for state to not be restored if required.

val webViewState = rememberSaveableWebViewState()
    val navigator = rememberWebViewNavigator()

    LaunchedEffect(navigator) {
        val bundle = webViewState.viewState
        if (bundle == null) {
            // This is the first time load, so load the home page.
            navigator.loadUrl("https://bbc.com")
        }
    }

    WebView(
        state = webViewState,
        navigator = navigator,
        modifier = Modifier.fillMaxSize()
    )

As part of this refactor, a new API was introduced that allows custom LayoutParams to be passed into the WebView composable. There are now two entry points, one that attempts to size itself based on Modifier constraints and one where you must pass in the appropriate LayoutParams to size the WebView correctly.

Fixes #1178 Fixes #1407 Fixes #1435 Fixes #1563 Fixes #1573 Fixes #1564

bentrengrove commented 1 year ago

It will be in the next release in approximately two weeks time

bentrengrove commented 1 year ago

This has just been released to maven in 0.31.1-alpha

R4M5E5 commented 1 year ago

Is it somehow possible to hoist the webViewState and the navigator above the NavHost? So for example in the WebViewSaveStateSample.kt to call the rememberSaveableWebViewState() and the rememberWebViewNavigator() just right after the rememberNavController() call and then pass down the webViewState and the navigator to the Home composable via arguments?

So something like:

val navController = rememberNavController()
val webViewState = rememberSaveableWebViewState()
val navigator = rememberWebViewNavigator()

LaunchedEffect(navigator) {
   val bundle = webViewState.viewState
   if (bundle == null) {
      // This is the first time load, so load the home page.
      navigator.loadUrl("https://bbc.com")
   }
}

NavHost(navController = navController, startDestination = "home") {
   composable("home") {
      Home(webViewState, navigator)
    }
   composable("detail") {
       Detail()
    }
}                   

Because for me this doesn't work. With this approach the webview is not keeping the state after navigating. Any idea how to make this work?

rafakob commented 1 year ago

Is there a way to remember WebView state which is in a LazyColumn item? I'm testing the rememberSaveableWebViewState but when I scroll away from that item and go back to it - WebView refreshes the page.

YugeCse commented 1 year ago

I put a webview into a ScrollableControlView, Then I click one button, and the page navigates to annother page. Then, I back to the webview page, the webview refreshes the page. It loss its scroll position.

Box(Modifier.fillMaxSize().verticalScroll(rememberScrollState())){ Button(Modifier.click(gotoAnnotherPage)){ Text('NEXT PAGE') } WebView(Modifier.fillMaxWidth().wrapContentHeight()) Text('Hello , this is a test!') }

Is there any way to remember the scroll position? Thank you!

nickboris commented 1 year ago

Thank you @bentrengrove for adding this functionality, I think it's a great step in making webviews easier to manage with compose. I wanted to second the use case that @rafakob mentioned above. I have a small webview element being displayed in a lazy column that I can't revert to a non-recycling column due to performance concerns, and the reloads are quite jarring from a UX perspective. Will be following this thread to see if there are any updates/plans to help support this use case in the future.