Camouflage the Status Bar with Edge-to-Edge Jetpack Compose Screens and Dialogs | by Katie Barnett | Jan, 2024
Ditch the jarring contrast of dark system bars against your vibrant app visuals. Edge-to-edge drawing in Jetpack Compose lets you transform those bars into chameleons, adapting to your UI’s colors and textures. Watch as they melt into the background, creating a unified canvas that captivates users.
While edge-to-edge with Jetpack Compose is a breeze for most screens, dialogs require a dash of finesse to truly camouflage those system bars and deliver a seamless, immersive experience. No matter where users encounter these interactive pop-ups, they’ll be whisked away to a place where boundaries vanish and content reigns supreme!
Let’s first start with a basic screen, a nice header image of some lovely clown fish. But unfortunately, with an ugly grey status bar at the top!
What we want to do is expand the content to be drawn under the top status bar and under the navigation bar at the bottom to give that an immersive experience while still allowing the user to see their normal status bar content and icons.
To do this we just need to add a simple
1.8.0-alpha03 and later) at the top of
onCreate in the
MainActivity. This might be somewhat familiar if you used SystemUIController prior to the deprecation of Accompanist.
One thing we also need to do, is remove any status bar controlling from the Material Theme definition (sometimes this is added as part of the Android Studio new project template). This is the common cause of finding
enableEdgeToEdge not working.
Giving this a try…
There, nice and easy, the app looks so much better with the top status bar and the bottom navigation bar blending into the background. It is easy to see the white status bar icons on the image!
But there is an issue, my device is currently in dark mode, if I switch it to light mode we can see the status bar is not so easy to read:
What is happening here is that
enableEdgeToEdge() by default sets the
SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT) which means that the icon color will change depending if the device is in dark or light mode (white icons for dark mode, black for light mode).
If you know that the image behind the status bar will look best with either light or dark icons on top you can specifically set which icon type in the activity using the specific
enableEdgeToEdge(statusBarStyle = SystemBarStyle.light(Color.TRANSPARENT, Color.TRANSPARENT))
enableEdgeToEdge(statusBarStyle = SystemBarStyle.dark(Color.TRANSPARENT))
You can also set the same for the
Styling the scrim
In the above example images we can see that the status bar, while it is visible and we can select the icons color, if we have a more complex image it might still be hard to see the icons or read the time. The status bar is a bit too camouflaged!
For this, we can add a scrim beneath the status bar, replacing the
Color.TRANSPARENT values above with an integer
enableEdgeToEdge(statusBarStyle = SystemBarStyle.dark(Color.parseColor(“#801b1b1b”)))
Now the status bar is the right level of camouflaged — readable but not taking away from the app beauty.
This seems all good until you try and load some content in a dialog.
So if we have
enableEdgeToEdge set up in the main activity and show content in a
Dialog object we don’t get an edge-to-edge dialog, despite in the code adding
fillMaxSize to the modifiers:
The reduction in width here is due to the
platformDefaultWidth being applied, we can fix that by passing in
DialogProperties to the dialog with this disabled:
So now at least we have full width. But what about the status bar and navigation bar?
If we look super closely at the status bar, we can see that there is a semi transparent scrim and we can see through to the image underneath. This is not ideal!
enableEdgeToEdge functionality does not work here.
There is another
decorFitsSystemWindows which in the documentation implies that this will allow
WindowInsets to be toggled, yet it does not change the status bar. There are some issues raised that are still in an unfixed & won’t fix state to request that these properties be expanded to allow this.
True Edge-to-Edge Dialogs
We can work around this by doing the following:
- Find Activity and Dialog window (they are 2 different windows) and apply the edge-to-edge flags from the activity window to the dialog window, this will allow dialog window to draw under system bars.
- Update the dialog view parent layout params to match full screen using a
Credit for this idea goes to this StackOverflow answer from doolle89 — note, in this answer the transparency of the system bars was implemented via SystemUIController prior to the deprecation of Accompanist. The
enableEdgeToEdge method on the activity covers this now.
Note, in order for this to work we have to switch back to using the
Now we have a fully edge-to-edge dialog!
Navigation Destination Dialogs
You might be wondering, can the same be applied to
dialog destinations navigated to via a
NavHost. Why yes it can!
It works exactly the same!
Make it reusable
As always, we want to make sure code can be reused in lots of places. The above code will only work from an Activity where
window is available. Adding some helper functions to extract the window from the
Context, we can extract this out to a reusable function that can be called wherever we construct the dialog.
Don’t get too excited, this is going to be bad news for dialogs.
What if you are not sure about what color to set the icons to until runtime or if it changes depending on the image you want to show?
For example, this sunlight image does not work at all well with white colored icons:
Unfortunatly at this stage (at least from my investigation) calling
enableEdgeToEdge again with different
SystenBarStyle values will not alter the dialog. It will affect the activity screen underneath but not the dialog itself. To be able to modify this you can go back to using SystemUIController but given the deprecation of Accompanist this option is limited. Hopefully this will be fixed in the future!
- Mobile App Development (625)