The Matrix
The Matrix

Reputation: 1348

Actionbar in Android 15 is overlapping activity contents

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

Upvotes: 1

Views: 766

Answers (2)

Sanjay Mangaroliya
Sanjay Mangaroliya

Reputation: 4352

I hope this answer helps you

<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>

Note: Add in themes.xml and night\themes.xml

Upvotes: 1

Mohan Noone
Mohan Noone

Reputation: 721

I just did this for an app, it came to three steps: Note: rotation is not handled but may be possible with some adjustments.

  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 since the dimensions 
    //and color don't change in my use case, with no rotation
    private static CustomBackground standardInstance;
    
    private static CustomBackground instanceOf(Activity activity, Insets insets) {
       if (standardInstance == null) {
           DisplayMetrics m = new DisplayMetrics();
           activity.getWindowManager().getDefaultDisplay().getMetrics(m);
           standardInstance = new CustomBackground(m.widthPixels, m.heightPixels, activity.getColor(R.color.colorPrimary), insets); // Assuming R.color.colorPrimary is the available and the intended color for the status area
       } else {
           standardInstance.insets = insets;
       }
       return standardInstance;
    }
    
    
    private final int width;
    private final int height;
    private final int color;
    private final 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

Upvotes: 1

Related Questions