Wednesday, April 2, 2025
HomeAndroid app developmentMake WebViews edge-to-edge. Make your WebViews suitable with… | by Ash Nohe...

Make WebViews edge-to-edge. Make your WebViews suitable with… | by Ash Nohe | Android Builders | Mar, 2025


Guarantee your WebViews are suitable with Android 16, as Android 16 removes the power to opt-out of drawing your app edge-to-edge. The way in which you deal with insets for WebViews depends upon whether or not or not your app owns the online content material.

This submit assumes primary information of dealing with insets and is relevant in case your WebViews are drawing beneath system bars or show cutouts. See the Compose and Views documentation, and the Inset dealing with suggestions weblog for steerage on dealing with insets.

In the event you’re in search of steerage on easy methods to make your webpage edge-to-edge on Chrome, see the Chrome on Android edge-to-edge migration information as a substitute.

This submit covers the next subjects:

  • deal with WebViews in case your app doesn’t personal the online content material
  • deal with WebViews in case your app owns the online content material
  • Dealing with IME insets in WebViews

WebViews displaying exterior content material can’t simply draw edge-to-edge and may as a substitute be inset to keep away from the system bars and show cutout. The implementation is totally different relying on should you’re utilizing Compose or Views, however typically follows these steps:

  1. Wrap the WebView in a container and apply insets as padding on that container.
  2. Set the app’s background coloration in a best-effort try and match the webpage.
Three app screenshots showing WebView layout issues and fixes.
Determine 1. Left to proper. (a) The left picture reveals a full display screen WebView in an app concentrating on SDK 35, at which level edge-to-edge is enforced. The highest of the WebView collides with standing bar icons. (b) The center picture reveals the results of padding the WebView’s mother or father. The app’s background is ready to pink to make it obvious that the WebView is inset. (c) The best picture is the specified consequence. The app’s background is ready to white in a best-effort try and match the webpage.

See the next code samples.

Apply insets to a WebView in a Compose app

To make sure a WebView in Compose avoids overlapping with system bars, show cutout and keyboard, apply Modifier.windowInsetsPadding(WindowInsets.safeDrawing) to its wrapper (e.g. AndroidView). This gives the required padding to maintain the WebView content material inside the secure space of the display screen.

@Composable
enjoyable WebViewInCompose() {
AndroidView(
modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing),
manufacturing facility = { context ->
WebView(context).apply {
// Configure WebView choices right here
}
}
)
}

Then, replace your app’s background so it matches the WebView’s background as a lot as doable.

Apply insets to a WebView in a Views app

To make sure a WebView in Views avoids overlapping the system bars, show cutout and keyboard, wrap the WebView in a container like a FrameLayout and do one of many following:

  • Set android:fitsSystemWindows="true"
  • Use ViewCompat.setOnApplyWindowInsetsListener() and apply systemBars, displayCutout, and ime insets on the container. See the Views documentation for a code pattern utilizing the listener.

Lastly, replace android:windowBackground in your themes.xml so it matches the WebView’s background if doable.

In case your app owns the online content material, both pad the WebView’s mother or father as described above; or, use JavaScript to inject padding into the online web page to attract the web page edge-to-edge as described under.

To inject padding into the online web page, first add <meta title=”viewport” content material=”viewport-fit=cowl”> to your HTML.

<meta title="viewport" content material="viewport-fit=cowl, initial-scale=1" />

Second, outline CSS variables for high, proper, backside and left secure space insets, because the env(safe-area-inset-*) variables return 0px on Android on the time of penning this weblog.

/* CSS */
physique {
padding-top: var(--safe-area-inset-top);
padding-right: var(--safe-area-inset-right);
padding-bottom: var(--safe-area-inset-bottom);
padding-left: var(--safe-area-inset-left);
}

As a substitute of making use of insets on the WebView’s container, use JavaScript to go the insets to your CSS variables to pad the webpage. The implementation is totally different relying on should you’re utilizing Compose or Views, but it surely typically follows these steps:

  1. Retrieve the highest, proper, backside and left system bar, show cutout and IME insets as uncooked pixel values.
  2. Convert the uncooked pixel values to density unbiased pixels.
  3. Inject the density unbiased pixels into the CSS variables as CSS pixels. When the web site renders on the Android machine, the WebView converts the CSS pixels again to density unbiased pixels. See Assist totally different screens in internet apps for extra info.
  4. In Compose, recompose when the software program keyboard expands or collapses if relevant.
  5. In Views, dispatch insets when the webpage first masses.
Two app screenshots. Top: WebView overlapping system bars and cutout. Bottom: WebView correctly padded using JavaScript.
Determine 2. High to backside. (a) The highest picture reveals a full display screen WebView in an app concentrating on SDK 35, at which level edge-to-edge is enforced. The WebView collides with system bars and show cutout. (b) The underside picture reveals the results of utilizing JavaScript to inject padding into the webpage, which is the edge-to-edge consequence we wish.

See the next code samples.

Utilizing Compose and JavaScript to inject insets into internet pages

A code pattern displaying easy methods to use JavaScript to inject insets into webpages in a Compose app.

import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.basis.format.WindowInsets
import androidx.compose.basis.format.ime
import androidx.compose.basis.format.safeDrawing
import androidx.compose.ui.unit.Dp
...

@Composable
enjoyable MainScreen() {
Field(modifier = Modifier.fillMaxSize()) {

// Retrieve insets as uncooked pixels
val insets = WindowInsets.safeDrawing
WebViewInCompose(
initialUrl = "file:///android_asset/instance.html",
insets = insets
)
}
}

@SuppressLint("SetJavaScriptEnabled")
@Composable
enjoyable WebViewInCompose(
initialUrl: String,
insets: WindowInsets,
density: Density = LocalDensity.present,
layoutDirection: LayoutDirection = LocalLayoutDirection.present,
myWebViewClient: CustomWebViewClient = bear in mind { CustomWebViewClient(
insets, density, layoutDirection
) }
) {

// Do not apply insets to the container
AndroidView(
manufacturing facility = { context ->
WebView(context).apply {
webViewClient = myWebViewClient
settings.javaScriptEnabled = true
loadUrl(initialUrl)
}
}, replace = { view ->

// Updates webpage when software program keyboard expands or collapses.
// In case your webpage would not have an enter discipline that opens the
// software program keyboard, take away this line.
applySafeAreaInsetsToWebView(insets, density, layoutDirection, view)
}
)
}

class CustomWebViewClient(
non-public val insets: WindowInsets,
non-public val density: Density,
non-public val layoutDirection: LayoutDirection
) : WebViewClient(){

override enjoyable onPageFinished(view: WebView?, url: String?) {
tremendous.onPageFinished(view, url)

// Inject insets into the webpage as soon as the web page has totally loaded
applySafeAreaInsetsToWebView(insets, density, layoutDirection, view)
}
}

non-public enjoyable applySafeAreaInsetsToWebView(
insets: WindowInsets,
density: Density,
layoutDirection: LayoutDirection,
webView: WebView?){

// Convert uncooked pixels to density unbiased pixels
val high = insets.getTop(density).toDp(density).worth
val proper = insets.getRight(density, layoutDirection).toDp(density).worth
val backside = insets.getBottom(density).toDp(density).worth
val left = insets.getLeft(density, layoutDirection).toDp(density).worth

val safeAreaJs = """
doc.documentElement.fashion.setProperty('--safe-area-inset-top', '${high}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-right', '${proper}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-bottom', '${backside}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-left', '${left}px');
"""

// Inject the density unbiased pixels into the CSS variables as CSS pixels
webView?.evaluateJavascript(safeAreaJs, null)
}

non-public enjoyable Int.toDp(density: Density): Dp = with(density) { [email protected]() }

Utilizing Views and JavaScript to inject insets into internet pages

A code pattern displaying easy methods to use JavaScript to inject insets into webpages in a Views app.

import androidx.core.util.TypedValueCompat.pxToDp
import
androidx.core.view.WindowInsetsCompat.Kind.displayCutout
import androidx.core.view.WindowInsetsCompat.Kind.ime
import androidx.core.view.WindowInsetsCompat.Kind.systemBars
...

override enjoyable onCreate(savedInstanceState: Bundle?) {
...

val myWebView: WebView = findViewById(R.id.webView)
myWebView.settings.javaScriptEnabled = true
myWebView.loadUrl("file:///android_asset/instance.html")

ViewCompat.setOnApplyWindowInsetsListener(myWebView) { _, windowInsets ->

// Retrieve insets as uncooked pixels
val safeDrawingInsets = windowInsets.getInsets(
systemBars() or displayCutout() or ime()
)
val displayMetrics = myWebView.context.assets.displayMetrics

// Convert uncooked pixels to density unbiased pixels
val high = pxToDp(safeDrawingInsets.high.toFloat(), displayMetrics)
val proper = pxToDp(safeDrawingInsets.proper.toFloat(), displayMetrics)
val backside = pxToDp(safeDrawingInsets.backside.toFloat(), displayMetrics)
val left = pxToDp(safeDrawingInsets.left.toFloat(), displayMetrics)

val safeAreaJs = """
doc.documentElement.fashion.setProperty('--safe-area-inset-top', '${high}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-right', '${proper}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-bottom', '${backside}px');
doc.documentElement.fashion.setProperty('--safe-area-inset-left', '${left}px');
"""

// Inject the density unbiased pixels into the CSS variables as CSS pixels
myWebView.evaluateJavascript(safeAreaJs, null)

windowInsets
}

myWebView.webViewClient = object : WebViewClient() {
override enjoyable onPageFinished(view: WebView, url: String) {
tremendous.onPageFinished(myWebView, url)
// dispatch insets as a result of insets aren't utilized when the webpage first masses.
view.requestApplyInsets()
}
}
}

Notice: If the injected insets look too giant, it is perhaps as a result of your web site’s Viewport initial-scale is greater than 1. On this case, divide the highest, proper, backside, and left variables by the dimensions.

To make sure your internet web page appropriately adjusts when the on-screen keyboard (IME) seems, you have to additionally account for IME insets. The offered Compose and Views code instance already contains this by retrieving WindowInsets.safeDrawing() in Compose or WindowInsetsCompat.Kind.ime() in Views:

// Getting IME insets from the above Compose code pattern
// safeDrawing contains ime, systemBars, and displayCutout
WindowInsets.safeDrawing

// Getting IME insets from the above Views code pattern
val safeDrawingInsets = windowInsets.getInsets(
systemBars() or displayCutout() or ime()
)

Omitting IME insets will result in points the place the webpage content material is obscured by the keyboard. For instance, when the person faucets an HTML textual content enter and the IME expands, the webpage received’t resize, stopping the person from seeing content material hidden behind the keyboard. By together with IME insets, the webpage dynamically adjusts its format when the IME is displayed, making certain all content material stays accessible to the person.

Determine 3. Left (incorrect implementation) to proper (right implementation). (a) The left GIF reveals a full-screen WebView the place IME insets aren’t dealt with. When the IME seems, the person can’t scroll to view content material behind it. (b) The best picture reveals the identical WebView with right IME inset dealing with. After the IME seems, the person can scroll to entry the total webpage content material.

In abstract, making certain WebViews are suitable with an edge-to-edge show requires totally different approaches relying on whether or not the app owns the online content material. For exterior content material, wrap the WebView in a container and apply insets as padding. For owned content material, both pad the container or inject JavaScript to deal with insets inside the webpage.



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments