Handle Status Bar Insets In Compose
While working on a personal project, I ran into an issue caused by new Android behaviors, specifically the forced edge-to-edge mode starting from Android 15 (SDK 35).
The documentation is very clear about this: the intent is to force every app to modernize and draw its content under the system bars (or at least handle them explicitly).
Let’s take a closer look at the problem:

As you can see from the image, the status bar inset (the yellow area at the top) appears to be duplicated. The navigation bar, on the other hand, is correct. The image refers to the following code snippet:
|
|
By default, Scaffold should handle the insets for both system bars (status and navigation)
through the ScaffoldDefaults.contentWindowInsets parameter. This means that the paddingValues
parameter is provided to the lambda and should be applied to the main content,
which in my case is the outer Box composable.
Since we are applying the padding manually, we must then notify the system that we have handled,
or consumed, a portion of these insets.
So where is the mistake? Theoretically, the yellow area at the top should not be visible, because it should be drawn underneath the notification bar.
The point is that you don’t always want to draw under these bars. For some applications, it still makes sense to keep the traditional behavior, with a solid-colored status bar that is neither transparent nor translucent. To achieve this behavior, you need to pay attention to the Android version used by the user, and over the past few years, several solutions have been deprecated.
As of today, the correct approach seems to be the following:
|
|
For devices running versions prior to Android 15, you can still use the statusBarColor property,
while for newer versions you must handle the insets manually and color the status bar yourself.
The first thing you may notice is that, in this case, we are working with Views instead of Composables.
Fortunately, there is a bridge between the two worlds: if an inset is consumed at the View level, it will not be duplicated in Compose.
The issue with the previous snippet is exactly this.
The status bar space was not handled correctly, so Compose,
through Scaffold, ended up applying it again.
The return value of setOnApplyWindowInsetsListener must remove,
from the original insets, the portion that has already been consumed.
Fixing the implementation accordingly:
|
|
Now the insets are calculated and handled correctly.
