18

I'm not defining any Toolbar in my XML files and I'm using the default ActionBar defined at theme:

<style name="AppBaseTheme" parent="@style/Theme.AppCompat.DayNight.DarkActionBar">
    <item name="colorAccent">@color/secondary</item>
    <item name="android:actionBarStyle">@style/AppBaseTheme.ActionBarStyle</item>
    <item name="actionBarStyle">@style/AppBaseTheme.ActionBarStyle</item>
    <item name="android:textViewStyle">@style/RobotoTextViewStyle</item>
    <item name="android:buttonStyle">@style/RobotoButtonStyle</item>        
    <item name="android:windowContentOverlay">@null</item>
</style>  

  

No issues in Android 14 and previous, but in Android 15 the Activity contents is displayed at fullscreen and ActionBar is overlapping the Activity contents.

It's possible to prevent it then have the same behavior in Android 15 I have in previous versions?

Thanks

2
  • in res/values-v35/styles <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item> Commented Dec 11, 2024 at 5:40
  • Thanks for the answer. I have tried it but doesn't work. Finally it had work when I have added android:fitsSystemWindows="true" to the root activity layout Commented Dec 12, 2024 at 7:26

7 Answers 7

31

I hope this answer is helpful to you.

<item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>

Note: Add this in themes.xml and night/themes.xml.

Sign up to request clarification or add additional context in comments.

3 Comments

Need to add into values-35 -> styles.xml or themes.xml folder
thk u very much~
Doesn't work for Android 16 (api level 36).
4
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="android:fitsSystemWindows">true</item>
        <item name="android:windowOptOutEdgeToEdgeEnforcement" tools:targetApi="35">true</item>

Comments

3

I just did this for an app, it came to three steps:

  1. Set android:fitsSystemWindows="true" in the XML layout root. This fixes the overlap but leaves unsightly translucent bars in the system areas. The next two steps are to tackle this.
  2. Set a background image or drawable for the root view, either in the XML layout, or programmatically in code, to color the status bar area.
  3. Set getWindow().setNavigationBarContrastEnforced(false) in the activity - to remove shading under navigation button area, if required.

For 2&3 I made a custom drawable class (as a starting point that may be modified as per requirement):

import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

public class CustomBackground extends Drawable {

    static public void setDecorBackground(Activity activity) {
        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
            ViewGroup viewGroup = (ViewGroup) ((ViewGroup) activity
                    .findViewById(android.R.id.content)).getChildAt(0);
            //if required
            activity.getWindow().setNavigationBarContrastEnforced(false);
            //See https://developer.android.com/develop/ui/views/layout/edge-to-edge#handle-overlaps
            ViewCompat.setOnApplyWindowInsetsListener(viewGroup, (v, windowInsets) -> {
                Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
                v.setBackground(CustomBackground.instanceOf(activity, insets));
                //Required for the rest of the layout to remain aligned                     
                v.onApplyWindowInsets(windowInsets.toWindowInsets());
                return WindowInsetsCompat.CONSUMED;
           });
         }
    }

    //Reusing a static instance
    private static CustomBackground standardInstance;
    
    private static CustomBackground instanceOf(Activity activity, Insets insets) {
        DisplayMetrics m = new DisplayMetrics();
        activity.getWindowManager().getDefaultDisplay().getMetrics(m);

        TypedValue typedValue = new TypedValue();
        //Retrieve primaryColor from theme.. if using appcompat androidx.appcompat.R.attr.colorPrimary instead of android.R.attr.colorPrimary, 
        //and if using material design, use com.google.android.material.R.attr.colorPrimary
    activity.getTheme().resolveAttribute(android.R.attr.colorPrimary, typedValue, true);
        int statusBarBgColor = typedValue.data; // Or directly from the theme's statusBarColor attribute if available

        if (standardInstance == null) {
            standardInstance = new CustomBackground(m.widthPixels, m.heightPixels, statusBarBgColor, insets); 
        } else {
            standardInstance.width = m.widthPixels;
            standardInstance.height = m.heightPixels;
            standardInstance.insets = insets;
            standardInstance.color = statusBarBgColor;
        }
       return standardInstance;
    }
    
    
    private int width;
    private int height;
    private int color;
    private Insets insets;
    private CustomBackground(int width, int height, int color, Insets insets) {
        this.width = width;
        this.height = height;
        this.color = color;
        this.insets = insets;
    }
    
    @Override
    public void draw(@NonNull Canvas canvas) {
    
       Paint paint = new Paint();
       paint.setColor(color);
    
            
       if (insets.top>0) {
           canvas.drawRect(0, 0, width, insets.top, paint);
        }

        // For additional sides
        /*if (insets.left>0) {
            canvas.drawRect(0, 0, insets.left, height, paint);
         }
        if (insets.bottom>0) {
           canvas.drawRect(0, height-insets.bottom, width, height, paint);
        }
        if (insets.right>0) {
         canvas.drawRect(width-insets.right, 0, width, height, paint);
        }*/
    }
    
   @Override
   public void setAlpha(int alpha) {
    
   }
    
   @Override
   public int getIntrinsicWidth() {
        return width;
   }
    
   @Override
   public int getIntrinsicHeight() {
        return height;
   }
    
   @Override
   public void setColorFilter(@Nullable ColorFilter colorFilter) {
    
   }
    
   @Override
   public int getOpacity() {
       return PixelFormat.TRANSLUCENT;
   }
}

To use this in an activity call CustomBackground.setDecorBackground(this) in onCreate.

To remove the shadow of the action bar, follow this: https://stackoverflow.com/a/27203224/4171025

1 Comment

getWindow().setNavigationBarContrastEnforced(false) This requires min API 29
3

You can fix it as below

  1. Enable edge-to-edge display
 EdgeToEdge.enable(this);

2. Apply the top inset as margin to your toolbar (or any custom view)

 ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> {
            Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
            layoutParams.topMargin = insets.top;
            v.setLayoutParams(layoutParams);
            return windowInsets;
        });

Update your onCreate() method as below

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Enable edge-to-edge display
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_main);
        
        Toolbar toolbar = findViewById(R.id.rootToolbar); // Or use some custom-view
        // Apply the top inset as margin to your toolbar
        ViewCompat.setOnApplyWindowInsetsListener(toolbar, (v, windowInsets) -> {
            Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
            ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
            layoutParams.topMargin = insets.top;
            v.setLayoutParams(layoutParams);
            return windowInsets;
        });
    }

Comments

0

Set android:fitsSystemWindows="true" worked in my case as well.

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

windowOptOutEdgeToEdgeEnforcement method will not work on Android 16+ (API level 36+): https://developer.android.com/about/versions/16/behavior-changes-16#edge-to-edge

Solution (call in MainActivity):

//Fix statusBar color
WindowInsetsControllerCompat(window, window.decorView).isAppearanceLightStatusBars = true

//Fix top (statusBar + actionBar) and bottom (system navigation bar) issue
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, insets ->
    val systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())

    view.setPadding(0, systemBarInsets.top, 0, systemBarInsets.bottom)

    WindowInsetsCompat.CONSUMED
}

Comments

0

For android 15+
set view in xml and set it as status bar


<View
    android:id="@+id/statusBarBackground"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    app:layout_constraintTop_toTopOf="parent"
    android:background="@color/statusBarColor"/>

Set as status bar so that top bar will not be tranparent


//for android 15+
View statusBarBg = findViewById(R.id.statusBarBackground);
setStatusBar(this, statusBarBg);

Now if view is still going up then add to the layout which is shifting dont add it to main parent layout


android:fitsSystemWindows="true"

<LinearLayout
    android:id="@+id/ll"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    android:orientation="vertical">

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.