You can make your app display edge-to-edge—using the entire width and height of the display—by drawing behind the system bars. The system bars are the status bar and the navigation bar.
To implement an edge-to-edge layout, your app must do the following:
- Draw behind the navigation bar to achieve a more compelling and modern user experience.
- Draw behind the status bar if it makes sense for your content and layout,
such as in the case of full-width imagery. To do this, use APIs such as
AppBarLayout
, which defines an app bar pinned to the top of the screen.
To implement an edge-to-edge layout in your app, perform the following steps:
- Lay out your app full-screen.
- Change the system bar colors and transparency.
- Handle any visual overlaps.

Lay out your app in full screen
Use WindowCompat.setDecorFitsSystemWindows(window,
false)
to lay out your app behind the system bars, as shown in the following code
example:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) WindowCompat.setDecorFitsSystemWindows(window, false) }
Java
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); WindowCompat.setDecorFitsSystemWindows(getWindow(), false); }
Change the color of the system bars
When operating in an edge-to-edge layout, your app needs to change the colors of the system bars to let the content underneath be visible. After your app performs this step, the system handles all visual protection of the user interface in gesture navigation mode and in button mode.
- Gesture navigation mode: the system applies dynamic color adaptation in which the contents of the system bars change color based on the content behind them. In the following example, the handle in the navigation bar changes to a dark color when it's above light content and to a light color when it's above dark content.
- Button mode: the system applies a translucent scrim behind the system bars (for API level 29 or later) or a transparent system bar (for API level 28 or earlier).

- Status bar content color: controls the color of status bar content, such as the time and icons.

You can edit the themes.xml
file to set the color of the navigation bar and,
optionally, to set the status bar as transparent and status bar content color as
dark.
<!-- values-v29/themes.xml -->
<style name="Theme.MyApp">
<item name="android:navigationBarColor">
@android:color/transparent
</item>
<!-- Optional: set to transparent if your app is drawing behind the status bar. -->
<item name="android:statusBarColor">
@android:color/transparent
</item>
<!-- Optional: set for a light status bar with dark content. -->
<item name="android:windowLightStatusBar">
true
</item>
</style>
You can use the
WindowInsetsController
API
directly, but we strongly recommend using the Support Library
WindowInsetsControllerCompat
where possible. You can use the WindowInsetsControllerCompat
API instead of
theme.xml
to control the status bar's content color. To do so, use the
setAppearanceLightNavigationBars()
function, passing in true
to change the foreground color of the navigation to
a light color or false
to revert to the default color.
Kotlin
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView) windowInsetsController?.isAppearanceLightNavigationBars = true
Java
WindowInsetsControllerCompat windowInsetsController = ViewCompat.getWindowInsetsController(getWindow().getDecorView()); if (windowInsetsController == null) { return; } windowInsetsController.setAppearanceLightNavigationBars(true);
Handle overlaps using insets
After you implement an edge-to-edge layout with color transparency, some of your app's views might draw behind the system bars, as shown in figure 6.
You can address overlaps by reacting to insets, which specify which parts of the screen intersect with system UI such as the navigation bar or the status bar. Intersecting can mean displaying above the content, but it can also inform your app about system gestures.
The types of insets that apply to displaying your app edge-to-edge are:
System bars insets: best for views that are tappable and that must not be visually obscured by the system bars.
System gesture insets: for gesture-navigational areas used by the system that take priority over your app.
System bars insets
System bar insets are the most commonly used type of insets. They represent the area where the system UI displays in the Z-axis above your app. They are best used to move or pad views in your app that are tappable and that must not be visually obscured by the system bars.
For example, the floating action button (FAB) in figure 6 is partially obscured by the navigation bar:

To avoid this kind of visual overlap in either gesture mode or button mode, you
can increase the view's margins using
getInsets(int)
with
WindowInsetsCompat.Type.systemBars()
.
The following code example shows how to implement system bar insets:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) // Apply the insets as a margin to the view. This solution sets // only the bottom, left, and right dimensions, but you can apply whichever // insets are appropriate to your layout. You can also update the view padding // if that's more appropriate. view.updateLayoutParams<MarginLayoutParams>( leftMargin = insets.left, bottomMargin = insets.bottom, rightMargin = insets.right, ) // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()); // Apply the insets as a margin to the view. This solution sets only the // bottom, left, and right dimensions, but you can apply whichever insets are // appropriate to your layout. You can also update the view padding if that's // more appropriate. MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams(); mlp.leftMargin = insets.left; mlp.bottomMargin = insets.bottom; mlp.rightMargin = insets.right; v.setLayoutParams(mlp); // Return CONSUMED if you don't want want the window insets to keep passing // down to descendant views. return WindowInsetsCompat.CONSUMED; });
If you apply this solution to the example shown in figure 6, it results in no visual overlap in button mode, as shown in figure 7:

The same applies to gesture navigation mode, as shown in figure 8:

System gesture insets
System gesture insets represent the areas of the window where system gestures take priority over your app. These areas are shown in orange in figure 9:

Like the system bar insets, you can avoid overlapping the system gesture insets
using
getInsets(int)
with
WindowInsetsCompat.Type.systemGestures()
.
Use these insets to move or pad swipeable views away from the edges. Common use
cases include bottom sheets,
swiping in games, and carousels implemented using
ViewPager2
.
On Android 10 or later, system gesture insets contain a bottom inset for the home gesture, and a left and right inset for the back gestures:

The following code example shows how to implement system gesture insets:
Kotlin
ViewCompat.setOnApplyWindowInsetsListener(view) { view, windowInsets -> val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()) // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.updatePadding(insets.left, insets.top, insets.right, insets.bottom) // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. WindowInsetsCompat.CONSUMED }
Java
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> { Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemGestures()); // Apply the insets as padding to the view. Here, set all the dimensions // as appropriate to your layout. You can also update the view's margin if // more appropriate. view.setPadding(insets.left, insets.top, insets.right, insets.bottom); // Return CONSUMED if you don't want the window insets to keep passing down // to descendant views. return WindowInsetsCompat.CONSUMED; });
Immersive mode
Some content is best experienced in full screen, giving the user a more
immersive experience. You can hide the system bars an for immersive mode using
the WindowInsetsController
and
WindowInsetsControllerCompat
libraries:
Kotlin
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView) // Hide the system bars. windowInsetsController.hide(Type.systemBars()) // Show the system bars. windowInsetsController.show(Type.systemBars())
Java
WindowInsetsControllerCompat windowInsetsController = ViewCompat.getWindowInsetsController(getWindow().getDecorView()); if (windowInsetsController == null) { return; } // Hide the system bars. windowInsetsController.hide(WindowInsetsCompat.Type.systemBars()); // Show the system bars. windowInsetsController.show(WindowInsetsCompat.Type.systemBars());
Refer to Hide system bars for immersive mode for more information about implementing this feature.
Additional resources
See the following references for more information about WindowInsets
, gesture
navigation, and how insets work: