Going edge-to-edge with Compose without losing it

Costa Fotiadis
ProAndroidDev
Published in
4 min readMar 13, 2024

--

Featured in Android Weekly Issue #614

Watching YouTube, one might notice a nice lighting effect going on around the edges of a video.

This is Ambient Mode. It’s a lighting effect that surrounds a YouTube video with a soft, glowing light that usually reflects the colors featured in the video itself.

The effect seems to be taking advantage of the whole screen. This includes the space right where the clock, notifications and other system related functionalities reside.

In other words, the system status bar.

While the video player component can be dragged down to a mini-player, the lighting effect itself stays where it is. It slowly loses its alpha, until it is not visible at all anymore when the video player is fully minimized.

Quite nice eh?

Housekeeping

The goal of this post is to figure out how to use Window Insets and display content edge-to-edge in Compose.

Imitation is the sincerest form of flattery, so let’s try to copy what YouTube does in 5 minutes — badly. 💀

TL;DR

Besides a stale meme, what do we have here?

  • Edge-to-edge effect
    - Background is fully covered by the app, system bars included
  • A space behind the system status bar where color/alpha can be manipulated
    - Bright red when the doggo is fully expanded, faint red when contracted
  • Control of the status bar icon tint
    - Light, in this case, to contrast the dark background
  • A resizable box (bonk included), playing the role of the video player

Setting up the theme

A normal theme will do.

To avoid confusion, anything handling system bars in the XML theme is a no-no.

Sidenote on theming

All compose theming below uses hard-coded colors for brevity.

Theming with respect to light/dark/dynamic color schemes should ideally be implemented depending on your needs.

Enable edge-to-edge

Since we want our app to display content behind the system UI and cover the whole screen, it would be nice to make the system bars completely transparent.

This can be accomplished with enableEdgeToEdge():

SystemBarStyle.auto handles the icon tint automatically. Meaning:

  • In light mode, icon tint will be dark
    - The system expects to have some sort of light color background behind the icons. That way they contrast nicely and are clearly visible
  • The opposite happens for dark mode — i.e. icon tint will be light

Time to test it

Light mode + auto = dark icons. They are barely discernible. 😰

Let’s fix that.

Scaffolding

Usually, the first thing someone adds at the top level is a Scaffold. Let’s make it black and draw on top this ugly blue color.

While we are at it, fix the status bar icon tint with a LaunchedEffect.

SystemBarStyle.dark is signalling to the system that we have a dark background occupying the status bar space.

To that end, light icon tint will be provided, for a nice contrast.

hey, it works

Handling insets manually

Scaffold provides paddingValues to help avoid the system bars. Normally, these paddings would be assigned as is, to the first child container.

Let’s use them, with a slight twist:

What is happening here?

  • We ensure that important content and interactions are not obscured by the system UI, with paddingValues.calculateStartPadding, and equivalents
  • Since we do want to draw behind the status bar, the top padding is omitted
  • Finally, a red-colored Spacer is positioned right where the status bar is, matching its exact height with windowInsetsTopHeight(WindowInsets.statusBars)

Bonus round — Implementing a resizable and draggable Box

Now that the system bars are taken care of, time for the poor man’s video player.

This is the part where someone can get really clever with some compose magic.

Gesture/scroll detection, advanced math and graceful recalculation of dimensions/colors, in order to save CPU cycles and the UI thread from being overloaded.

Unfortunately, I am way too stupid for that. A simple caveman solution based on detectVerticalGestures will do.

The complete solution is way too long-winded for this little blog. You can find it here if you are curious.

All that’s left is actually implementing the YouTube UI.

One clap = one prayer 🙏, and I’ll get right on it on part 2. (lie)

Anyways

Hope you found this somewhat useful.

@ markasduplicate

Later.

--

--