In modern Android development, utilizing the full screen real estate is crucial for creating immersive user experiences. Edge-to-edge display support, often referred to as going “full bleed,” allows your app to draw content behind the system bars (status and navigation bars), creating a seamless and modern look. This article provides a comprehensive guide on how to implement edge-to-edge display support in your Android applications using Kotlin and XML.
What is Edge-to-Edge Display?
Edge-to-edge display refers to the practice of drawing your app’s content behind the system bars, making use of the entire screen. This is typically achieved by making the system bars transparent or translucent, allowing the app’s content to show through.
Why Implement Edge-to-Edge?
- Immersive Experience: Provides a more engaging user interface.
- Modern Look: Aligns with contemporary design trends.
- Better Space Utilization: Maximizes screen real estate.
Steps to Implement Edge-to-Edge Display Support
Here’s a step-by-step guide on how to implement edge-to-edge display support in your Android app:
Step 1: Update Dependencies
First, ensure your project uses a Material Components theme, and your build.gradle file includes the necessary dependencies. Update your app’s build.gradle file:
dependencies {
implementation("com.google.android.material:material:1.6.0") // Or later
implementation("androidx.core:core-ktx:1.7.0") // Or later
}
Sync your project after updating the dependencies.
Step 2: Set Theme for Edge-to-Edge Support
Update your app’s theme to enable edge-to-edge support. In your res/values/styles.xml file, ensure you’re using a Material Components theme and set the necessary flags:
<resources>
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowLightStatusBar">true</item> <!-- Light status bar -->
<item name="android:windowLightNavigationBar">true</item> <!-- Light navigation bar -->
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>
android:windowLightStatusBar: Sets the status bar icons to be dark (for light backgrounds).android:windowLightNavigationBar: Sets the navigation bar icons to be dark (for light backgrounds).android:navigationBarColor: Makes the navigation bar transparent.android:statusBarColor: Makes the status bar transparent.android:windowDrawsSystemBarBackgrounds: Allows the app to draw behind the system bars.
Step 3: Implement in Kotlin Activity
In your main Activity, use the WindowCompat API to configure the window for edge-to-edge display:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable edge-to-edge display
WindowCompat.setDecorFitsSystemWindows(window, false)
setContentView(R.layout.activity_main)
}
}
WindowCompat.setDecorFitsSystemWindows(window, false): This line is essential. It tells the system that your app wants to handle the insets (the areas covered by system bars) itself, allowing your app to draw behind them.
Step 4: Adjusting Layout to Account for System Bars
After enabling edge-to-edge, your content might be obscured by the system bars. Use the Padding or Margin to ensure your content is visible.
Using View.OnApplyWindowInsetsListener
Apply insets to your views to prevent content from being hidden. In your layout file (activity_main.xml), give the root view an ID, for example, main_container.
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Edge-to-Edge!"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
Now, adjust your Kotlin activity:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.ViewCompat
import androidx.core.view.OnApplyWindowInsetsListener
import androidx.core.view.WindowInsetsCompat
import android.view.View
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable edge-to-edge display
WindowCompat.setDecorFitsSystemWindows(window, false)
setContentView(R.layout.activity_main)
val mainContainer = findViewById<View>(R.id.main_container)
ViewCompat.setOnApplyWindowInsetsListener(mainContainer) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
// Apply the top and bottom insets as padding to the view
view.setPadding(insets.left, insets.top, insets.right, insets.bottom)
WindowInsetsCompat.CONSUMED
}
}
}
ViewCompat.setOnApplyWindowInsetsListener: This listener allows you to react to window insets changes.windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()): Retrieves the system bar insets.view.setPadding(insets.left, insets.top, insets.right, insets.bottom): Applies the insets as padding to the view, ensuring content isn’t hidden.WindowInsetsCompat.CONSUMED: Indicates that the insets have been handled, preventing them from being passed further down the view hierarchy.
Step 5: Handling Light System Bars
If you have a light-themed app, ensure the status bar icons are dark for better visibility. Similarly, for dark-themed apps, use light icons.
import android.os.Build
import android.view.View
import androidx.core.view.WindowInsetsControllerCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Enable edge-to-edge display
WindowCompat.setDecorFitsSystemWindows(window, false)
setContentView(R.layout.activity_main)
val mainContainer = findViewById<View>(R.id.main_container)
ViewCompat.setOnApplyWindowInsetsListener(mainContainer) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(insets.left, insets.top, insets.right, insets.bottom)
WindowInsetsCompat.CONSUMED
}
// Set status bar icons to dark for light theme
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.isAppearanceLightStatusBars = true
// Optional: Handle navigation bar as well
windowInsetsController.isAppearanceLightNavigationBars = true
}
}
Key points:
WindowCompat.getInsetsController(window, window.decorView): Provides a controller to modify system bar appearance.windowInsetsController.isAppearanceLightStatusBars = true: Sets status bar icons to dark.windowInsetsController.isAppearanceLightNavigationBars = true: Sets navigation bar icons to dark (optional).
Complete Example
Here is a complete example combining all the steps to implement edge-to-edge display support in an Android app.
build.gradle
dependencies {
implementation("com.google.android.material:material:1.6.0") // Or later
implementation("androidx.core:core-ktx:1.7.0") // Or later
implementation("androidx.appcompat:appcompat:1.4.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.2")
}
styles.xml
<resources>
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="android:windowLightStatusBar">true</item> <!-- Light status bar -->
<item name="android:windowLightNavigationBar">true</item> <!-- Light navigation bar -->
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>
activity_main.xml
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Edge-to-Edge!"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.kt
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)
setContentView(R.layout.activity_main)
val mainContainer = findViewById<View>(R.id.main_container)
ViewCompat.setOnApplyWindowInsetsListener(mainContainer) { view, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
view.setPadding(insets.left, insets.top, insets.right, insets.bottom)
WindowInsetsCompat.CONSUMED
}
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.isAppearanceLightStatusBars = true
windowInsetsController.isAppearanceLightNavigationBars = true
}
}
Best Practices
- Test on Multiple Devices: Ensure compatibility and correct display on different screen sizes and Android versions.
- Consider Dark Theme: Adjust your theme to properly handle edge-to-edge in dark mode.
- Accessibility: Always prioritize accessibility. Ensure that content is readable and not obscured by system bars.
Conclusion
Implementing edge-to-edge display support enhances the user experience by creating a more immersive and modern interface. By following the steps outlined in this guide, you can effectively implement edge-to-edge in your Android apps using Kotlin and XML, making optimal use of the available screen real estate while ensuring your content remains accessible and visually appealing.