I just did this for an app, it came to three steps:
- 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.
- 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.
- 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