Tips to Display Edge-to-edge Screen Content in an Existing Android App in both Jetpack Compose & XML

Luke Simpson
5 min readJun 7, 2023

--

A lot of Android apps don’t implement edge-to-edge screens and it’s not surprising given how confusing it can be in the current world where apps contain both XML and Compose layouts. If done correctly, edge-to-edge screens — where the content runs behind the top system status bar and bottom system navigation bar — can give your app a professional, polished finish.

I recently added edge-to-edge to an existing Android codebase containing both XML and Jetpack Compose views and ran into a number of unexpected issues. While the approach would be slightly different if you were starting an app from scratch, here are six tips to help you implement edge-to-edge in your existing screen views as well as code snippets to demonstrate how you can make everything work together.

1. Use a Screen-by-Screen Approach in Existing Apps

If you’re modifying an existing app you probably won’t be able to get the desired effect with only global changes. For example, screens with bottom app navigation buttons might be better off without edge-to-edge implemented.

If you use a base fragment you can set a flag such as applyEdgeToEdge = false and override it in screens where the edge-to-edge changes should be applied.

2. Focus on the Bottom System Navigation Bar

It’s surprisingly easy to run into situations where the top status bar content, e.g. battery and wifi icons, are hard or impossible to read due to a lack of contrast or busy content running behind it. APIs like setAppearanceLightStatusBars can help but unless you’re doing something with photos or videos you might want to consider leaving the status bar in the default or primary background colour with the necessary padding to ensure content stays below it (more on that later). In my opinion the best effects of edge-to-edge are achieved when applied properly to the bottom system navigation bar.

3. Exclude OS Versions Below SDK 29 (Android Q)

One of the first things we’re told to do in the Android documentation is to set the bottom system navigation bar visibility to transparent. This is fine for Android devices on Android Q (SDK 29) or later where the bottom gesture navigation is available and selected.

However, users may still opt to use the older two- or three-button system navigation buttons or be on earlier versions of Android where this is the only option. When the transparent navigation bar colour is applied the button contrast can be completely lost depending on your theme settings — see image below on right with “missing” system navigation buttons.

Fortunately, in SDK 29 Android introduced an API to help ensure the correct contrast is achieved, which you can add to a v29/themes.xml:

<item name="android:enforceNavigationBarContrast">true</item>

See in the screenshot below the bottom system navigation bar has a tint that ensures buttons remain visible.

When each fragment is created you can choose to apply edge-to-edge while enforcing this using the following:

WindowCompat.setDecorFitsSystemWindows(
window = window,
decorFitsSystemWindows = applyEdgeToEdge.not() ||
Build.VERSION.SDK_INT < Build.VERSION_CODES.Q
)

4. Utilise Compose’s statusBarsPadding() & navigationBarsPadding()

When we enable edge-to-edge for a screen we are basically disabling the padding that keeps the entire screen content above and below the system navigation and status bars. But there are often times where content such as buttons need to have the appropriate padding re-applied so that they are accessible to users. The way we re-apply this padding is different in the Compose and XML worlds.

For screens using Compose, there are two helpful Modifier functions that apply the padding required to move any interactive elements such as buttons out from underneath the status or navigation bars. The magic part is how navigationBarsPadding() caters for both the taller button-based navigation bar and shorter gesture navigation bar.

5. Use Insets for Padding XML-based Screens

Similarly to the Compose approach outlined above, we use the system window insets values for any global positioning of XML layouts such as the system status bar.

ViewCompat.setOnApplyWindowInsetsListener(this) { _view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
_view.updateLayoutParams {
// Push all content below the top system status bar
topMargin = insets.top
}
WindowInsetsCompat.CONSUMED
}

6. Apply Edge-to-edge on Screens that Scroll to Achieve a Nice Look & Feel

Screens with a lot of content where users have to scroll are great candidates to target for edge-to-edge. In the example below we maximise the screen space by having content run directly under the transparent system gesture navigation bar.

Note that the colour of the gesture navigation bar changes depending on the content behind it in order to provide good contrast.

Lots more developer-focussed Android content available at https://appkitchen.dev.

--

--