17.9 C
London
Tuesday, September 3, 2024

Insets dealing with ideas for Android 15’s edge-to-edge enforcement | by Ash Nohe | Android Builders | Sep, 2024


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. App has dealt with insets, however feels much less immersive as a result of content material doesn’t scroll behind system bars.
// 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. App shows edge-to-edge and the final listing merchandise is totally seen. That is the end result we would like.
<!-- 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.

Determine 14. Left: The enter subject on the backside is obscured by the system’s navigation bar after concentrating on SDK 35. Center: Scaffold’s PaddingValues utilized to the enter subject. The system makes use of the scale of the standing bar and the highest app bar to calculate the highest padding worth, which creates extra padding above the enter subject. Proper: Scaffold’s PaddingValues utilized however with high padding manually eliminated.

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.

Determine 15. Edge-to-edge enforced. Left: fitsSystemWindows=false (the default). Proper: fitsSystemWindows=true. This isn’t the end result we would like as a result of the app doesn’t look edge-to-edge.
Determine 16. Edge-to-edge enforced, fitsSystemWindows=true. The hole on the left edge is because of a show cutout, which isn’t seen right here. This isn’t the end result we would like as a result of the app doesn’t look edge-to-edge.

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. Edge-to-edge enforced. Left: AppBarLayout doesn’t robotically deal with insets. Proper: Add fitsSystemWindows to AppBarLayout and CoordinatorLayout to attract edge-to-edge.
<!-- 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 set fitsSystemWindows=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 if fitsSystemWindows=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.

Documentation

Deal with edge-to-edge enforcements in Android 15 (Compose)

Latest news
Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here