We are able to use the window inset listener so that each one listing objects, together with the final listing merchandise, are padded above the navigation bar.
// Determine 12
ViewCompat.setOnApplyWindowInsetsListener(
findViewById(R.id.recycler_view)
) { v, insets ->
val innerPadding = insets.getInsets(
// Discover we're utilizing systemBars, not statusBar
WindowInsetsCompat.Sort.systemBars()
// Discover we're additionally accounting for the show cutouts
or WindowInsetsCompat.Sort.displayCutout()
// If utilizing EditText, additionally add
// "or WindowInsetsCompat.Sort.ime()"
// to take care of focus when opening the IME
)
v.setPadding(
innerPadding.left,
innerPadding.high,
innerPadding.proper,
innerPadding.backside)
insets
}
Nevertheless, now the app appears to be like much less immersive. To get the end result we would like, add clipToPadding=false
to make sure the final listing merchandise sits above the navigation bar and the listing is seen whereas scrolling behind the navigation bar (and standing bar).
<!-- Determine 13 -->
<RecyclerView
...
android:clipToPadding="false" />
5. Don’t neglect IMEs
Set android:windowSoftInputMode=”adjustResize”
in your Exercise’s AndroidManifest.xml entry to make room for the IME (or tender keyboard) on display.
Dealing with IMEs insets in Compose
Account for the IME utilizing Modifier.imePadding()
. For instance, this will help keep deal with a TextField
in a LazyColumn
when the IME opens. See the Inset consumption part for a code instance and clarification.
Dealing with IMEs insets in Views
Earlier than concentrating on SDK 35, utilizing android:windowSoftInputMode=”adjustResize”
was all you wanted to take care of deal with — for instance — an EditText
in a RecyclerView
when opening an IME. With “adjustResize”
, the framework handled the IME because the system window, and the window’s root views have been padded so content material avoids the system window.
After concentrating on SDK 35, you will need to additionally account for the IME utilizing ViewCompat.setOnApplyWindowInsetsListener
and WindowInsetsCompat.Sort.ime()
as a result of the framework will not pad the window’s root views. See Determine 12’s code instance.
6. For backward compatibility, use enableEdgeToEdge
as an alternative of setDecorFitsSystemWindows
After your app has dealt with insets, make your app edge-to-edge on earlier Android variations. For this, use enableEdgeToEdge
as an alternative of setDecorFitsSystemWindows
. The enableEdgeToEdge
methodology encapsulates the about 100 strains of code it is advisable be really backward suitable.
7. Background shield system bars solely when crucial
In lots of instances, hold the brand new Android 15 defaults. The standing bar and gesture navigation bar ought to be clear, and three button navigation translucent after concentrating on SDK 35 (see Determine 1).
Nevertheless, there are some instances the place you want to protect the background colour of the system bars, however the APIs to set the standing and navigation bar colours are deprecated. We’re planning to launch an AndroidX library to assist this use case. Within the meantime, in case your app should supply customized background safety to 3-button navigation or the standing bar, you may place a composable or view behind the system bar utilizing WindowInsets.Sort#tappableElement()
to get the 3-button navigation bar peak or WindowInsets.Sort#statusBars
.
For instance, to indicate the colour of the factor behind the 3-button navigation in Compose, set the window.isNavigationBarContrastEnforced
property to false. Setting this property to false makes 3-button navigation totally clear (be aware: this property does not have an effect on gesture navigation).
Then, use WindowInsets.tappableElement
to align UI behind insets for tappable system UI. If non-0, the consumer is utilizing tappable bars, like three button navigation. On this case, draw an opaque view or field behind the tappable bars.
class MainActivity : ComponentActivity() {
override enjoyable onCreate(savedInstanceState: Bundle?) {
tremendous.onCreate(savedInstanceState)
setContent {
window.isNavigationBarContrastEnforced = false
MyTheme {
Floor(...) {
MyContent(...)
ProtectNavigationBar()
}
}
}
}
}// Use provided that required.
@Composable
enjoyable ProtectNavigationBar(modifier: Modifier = Modifier) {
val density = LocalDensity.present
val tappableElement = WindowInsets.tappableElement
val bottomPixels = tappableElement.getBottom(density)
val usingTappableBars = keep in mind(bottomPixels) {
bottomPixels != 0
}
val barHeight = keep in mind(bottomPixels) {
tappableElement.asPaddingValues(density).calculateBottomPadding()
}
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Association.Backside
) {
if (usingTappableBars) {
Field(
modifier = Modifier
.background(MaterialTheme.colorScheme.background)
.fillMaxWidth()
.peak(barHeight)
)
}
}
}
The next ideas apply just for apps that use Jetpack Compose. See further Compose-related ideas on this video: Edge-to-edge and insets | Compose Suggestions.
8. Use Scaffold’s PaddingValues
For Compose, use Scaffold
as an alternative of Floor
to prepare your app’s UI with TopAppBar
, BottomAppBar
, NavigationBar
, and NavigationRail
. Use Scaffold’s PaddingValues
parameter to inset your important UI. Generally, that’s all it is advisable do.
Nevertheless, there are instances the place making use of Scaffold’s PaddingValues
will trigger sudden outcomes. Scaffold’s PaddingValues
consists of insets for the highest, backside, begin and finish edges of the display. You might want values for less than sure edges. One method is to make a duplicate of the parameter and manually modify high, backside, begin and finish insets in order to not apply an excessive amount of padding.
Right here’s the wrong code, inflicting the surplus padding seen within the center picture of Determine 14.
// Causes extra padding, seen within the center picture of Determine 14.
Scaffold { innerPadding -> // innerPadding is Scaffold's PaddingValues
InputBar(
...
contentPadding = innerPadding
) {...}
}
Right here’s the corrected code that generates correct padding, as seen within the right-side picture of Determine 14.
// Operate to make a duplicate of PaddingValues, utilizing present defaults until an
// various worth is specified
personal enjoyable PaddingValues.copy(
layoutDirection: LayoutDirection,
begin: Dp? = null,
high: Dp? = null,
finish: Dp? = null,
backside: Dp? = null,
) = PaddingValues(
begin = begin ?: calculateStartPadding(layoutDirection),
high = high ?: calculateTopPadding(),
finish = finish ?: calculateEndPadding(layoutDirection),
backside = backside ?: calculateBottomPadding(),
)// Produces appropriate padding, seen within the right-side picture of Determine 14.
Scaffold { innerPadding -> // innerPadding is Scaffold's PaddingValues
val layoutDirection = LocalLayoutDirection.present
InputBar(
...
contentPadding = innerPadding.copy(layoutDirection, high = 0.dp)
) {...}
}
9. Use excessive degree WindowInsets APIs
Just like Scaffold’s PaddingValues
, you may as well use the high-level WindowInset
APIs to simply and safely draw important UI parts. These are:
See Inset fundamentals to study extra.
The next apply just for Views-based apps.
10. Choose ViewCompat.setOnApplyWindowInsetsListener
over fitsSystemWindows=true
You might use fitsSystemWindows=true
to inset your app’s content material. It’s a simple 1-line code change. Nevertheless, don’t use fitsSystemWindows
on a View that comprises your complete structure (together with the background). It will make your app look not edge-to-edge as a result of fitsSystemWindows
handles insets on all edges.
fitsSystemWindows
can create an edge-to-edge expertise if utilizing CoordinatorLayouts
or AppBarLayouts.
Add fitsSystemWindows
to the CoordinatorLayout
and the AppBarLayout
, and the AppBarLayout
attracts edge-to-edge, which is what we would like.
<!-- Determine 17 -->
<CoordinatorLayout
android:fitsSystemWindows="true"
...>
<AppBarLayout
android:fitsSystemWindows="true"
...>
<TextView
android:textual content="App Bar Format"
.../>
</AppBarLayout>
</CoordinatorLayout>
On this case, AppBarLayout
used fitsSystemWindows
to attract beneath the standing bar quite than avoiding it, which is the alternative of what we would count on. Moreover, AppBarLayout
with fitsSystemWindows=true
solely applies padding for the highest and never the underside, begin, or finish edges.
The CoordinatorLayout
and AppBarLayout
objects have the next conduct when overriding fitsSystemWindows
:
CoordinatorLayout
: backgrounds of kid views draw beneath the system bars if these views additionally setfitsSystemWindows=true
. Padding is robotically utilized to the content material of these Views (e.g. textual content, icons, photos) to account for system bars and show cutouts.AppBarLayout
: attracts beneath the system bars iffitsSystemWindows=true
and robotically applies high padding to content material.
Generally, deal with insets with ViewCompat.setOnApplyWindowInsetsListener
as a result of it permits you to outline which edges ought to deal with insets and has constant conduct. See ideas #4 and #11 for a code instance.
11. Apply insets based mostly on app bar peak throughout the structure section
If you happen to discover that your app’s content material is hiding beneath an app bar, you may want to use insets after the app bar is laid out, taking the app bar peak into consideration.
For instance, you probably have scrolling content material beneath an AppBarLayout
in a FrameLayout
, you possibly can use code like this to make sure the scrolling content material seems after the AppBarLayout
. Discover padding is utilized inside doOnLayout
.
val myScrollView = findViewById<NestedScrollView>(R.id.my_scroll_view)
val myAppBar = findViewById<AppBarLayout>(R.id.my_app_bar_layout)ViewCompat.setOnApplyWindowInsetsListener(myScrollView) { scrollView, windowInsets ->
val insets = windowInsets.getInsets(
WindowInsetsCompat.Sort.systemBars() or WindowInsetsCompat.Sort.displayCutout()
)
myAppBar.doOnLayout { appBar ->
scrollView.updatePadding(
left = insets.left,
proper = insets.proper,
high = appBar.peak,
backside = insets.backside
)
}
WindowInsetsCompat.CONSUMED
}
Likewise, you probably have scrolling content material that ought to sit above a BottomNavigationView
, you’ll need to account for the BottomNavigationView’s peak as soon as it’s laid out.
It’d take vital work to correctly assist an edge-to-edge expertise. Earlier than you goal SDK 35, take into account how lengthy it is advisable make the mandatory adjustments in your app.
If you happen to want extra time to deal with insets to be suitable with the system’s default edge-to-edge conduct, you may briefly opt-out utilizing R.attr#windowOptOutEdgeToEdgeEnforcement
. However do not plan to make use of this flag indefinitely as it will likely be non-functional within the close to future.
The flag is likely to be notably useful for apps which have tens to a whole lot of Actions. You may opt-out every Exercise, then — make your app edge-to-edge one Exercise at a time.
Right here’s one method to utilizing this flag. Assuming your minSDK is lower than 35, this attribute should be in values-v35.xml
.
<!-- In values-v35.xml -->
<assets>
<!-- TODO: Take away as soon as actions deal with insets. -->
<fashion title="OptOutEdgeToEdgeEnforcement">
<merchandise title="android:windowOptOutEdgeToEdgeEnforcement">true</merchandise>
</fashion>
</assets>
Create an empty fashion for previous variations in values.xml
:
<!-- In values.xml -->
<assets>
<!-- TODO: Take away as soon as actions deal with insets. -->
<fashion title="OptOutEdgeToEdgeEnforcement">
<!-- android:windowOptOutEdgeToEdgeEnforcement
is not supported earlier than SDK 35. This empty
fashion allows programmatically opting-out. -->
</fashion>
</assets>
Name the fashion earlier than accessing the decor view in setContentView
:
class MainActivity : AppCompatActivity() {
override enjoyable onCreate(savedInstanceState: Bundle?) {// Name earlier than the DecorView is accessed in setContentView
theme.applyStyle(R.fashion.OptOutEdgeToEdgeEnforcement, /* drive */ false)
tremendous.onCreate(savedInstanceState)
setContentView(R.structure.activity_main)
...
}
}
Android 15 AOSP launched at present. Our workforce has created blogs, movies, and codelabs to assist get your app able to deal with the Android 15 edge-to-edge enforcement. What follows is a listing of outdated and new assets for additional studying.