Reputation: 691
I'm trying to make an android launcher. I want to achieve a completely transparent status bar and navigation bar, here is my theme xml file.
<resources>
<style name="Theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>
</resources>
the last two items don't work, there is still a shadow on lollipop.
This is what it looks like(note there is actually a shadow on status bar and navigation bar):
what I want to achieve (nova launcher):
how to make the status bar and navigation bar "transparent" instead of "translucent"?
Upvotes: 69
Views: 139306
Reputation: 1312
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
This will get you a transparent system bars until api 29.
From api 29+ you need to add
<item name="android:enforceNavigationBarContrast">false</item>
this will stop the system from enforcing scrim color to ensure contrast -> on the left enforceNavigationBarContrast=true, on the right equal to false.
using only xml you will have to create two theme files like this ->
right click on themes folder -> new -> values resource files
in order to make all of this to work these attributes must be false as stated here, also if you just remove them from xml AND you are not setting the equivalent flags in code then they are turned off by default.
<item name="android:windowTranslucentNavigation">false</item>
<item name="android:windowTranslucentStatus">false</item>
also make sure that your view is full screen by setting
WindowCompat.setDecorFitsSystemWindows(window, false)
in onCreate
Extra
sometimes you will need to change nav/status bar icons in case they blends with the background, in this case you have two options, light/dark icons, to change them you need to add
<item name="android:windowLightNavigationBar">true</item>
<item name="android:windowLightStatusBar">true</item>
to do same changes i mentioned above but using code you will need these extensions functions
To change light status/nav bar
fun Window.setLightStatusBar(state: Boolean) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insetsController?.setSystemBarsAppearance(
/* appearance = */ if (state) 0 else APPEARANCE_LIGHT_STATUS_BARS,
/* mask = */ APPEARANCE_LIGHT_STATUS_BARS
)
} else {
decorView.systemUiVisibility = if (state) 0 else SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}
}
fun Window.setLightNavigationBar(state: Boolean) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insetsController?.setSystemBarsAppearance(
/* appearance = */ if (state) 0 else APPEARANCE_LIGHT_NAVIGATION_BARS,
/* mask = */ APPEARANCE_LIGHT_NAVIGATION_BARS
)
} else {
decorView.systemUiVisibility = if (state) 0 else SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
}
To set nav bar contrast
fun Window.setNavigationBarContrastEnforcedIfSupported(enabled: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
isNavigationBarContrastEnforced = enabled
}
}
to change colors to transparent
window.setNavigationBarContrastEnforcedIfSupported(false)
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.TRANSPARENT
pay special attention that
calling setNavigationBarContrastEnforcedIfSupported must happen before setting nav bar color to transparent otherwise it will not take effect
if you are changing system bar light mode by code then you must remove any
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
from xml otherwise it will not work, somehow when you use the deprecated decorView.systemUiVisibility
-which is used by the xml attributes i guess- then when you try to mix its use with insetsController?.setSystemBarsAppearance
they both stop to working properly, check this answer for more info
also here is a good article about system bars colors
Upvotes: 1
Reputation: 11228
Update: Just use androidx.activity.enableEdgeToEdge()
instead
Outdated:
Based on Arpan Sarkar answer just made use of WindowCompat to reduce amount of code and avoid uses of deprecated definitions,
fun Activity.transparentSystemBars(
behindStatusBarIsLight: Boolean,
behindNavigationBarIsLight: Boolean,
) {
// Android 4 is hard to debug and apparently ViewCompat.setOnApplyWindowInsetsListener isn't
// reporting any value there so let's skip and simplify
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return
WindowCompat.setDecorFitsSystemWindows(window, false)
if (behindStatusBarIsLight || behindNavigationBarIsLight) {
val insetsController: WindowInsetsControllerCompat =
WindowCompat.getInsetsController(window, window.decorView)
if (behindStatusBarIsLight)
insetsController.isAppearanceLightStatusBars = true
if (behindNavigationBarIsLight)
insetsController.isAppearanceLightNavigationBars = true
}
val isLightStatusBarAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
val isLightNavigationBarAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
val shouldStatusBarBeTransparent = !behindStatusBarIsLight || isLightStatusBarAvailable
val shouldNavigationBarBeTransparent = !behindNavigationBarIsLight || isLightNavigationBarAvailable
val systemUiScrim = ColorUtils.setAlphaComponent(Color.BLACK, 0x40) // 25% black
window.statusBarColor = if (shouldStatusBarBeTransparent) Color.TRANSPARENT else systemUiScrim
window.navigationBarColor = if (shouldNavigationBarBeTransparent) Color.TRANSPARENT else systemUiScrim
// You may set android:enforceNavigationBarContrast to false in style.xml as doing it in code isn't as effective apparently.
}
There is also EdgeToEdgeUtils.applyEdgeToEdge in the Material library which works but isn't supposed to be used by regular developers, guess it will be provided to the public someday.
Upvotes: 0
Reputation: 1353
fun Activity.setTransparentStatusBar() {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.TRANSPARENT
window.navigationBarColor = Color.TRANSPARENT
}
That's it
Upvotes: 0
Reputation: 647
This is for the new guys like myself on Nativescript + Angular. I started off with one of the blank templates on the NTS marketplace. Then For my specific use, I need the status bar on top to be always transparent (similar to the iOS style) and the navbar (bottom) to be fully transparent (not translucent!) on some components/modules, while opaque in others. If everything is done according to the protocol set by NTS, you should have a main.ts (a prerequisite for my solution) similar to this
I separated my work into two pieces, top first, then the bottom. For the top I found this answer that worked. So you should have a main.ts file that looks like this.
import { platformNativeScriptDynamic } from "@nativescript/angular";
import { AppModule } from "./app/app.module";
import * as application from "tns-core-modules/application";
import { Color } from "@nativescript/core";
platformNativeScriptDynamic().bootstrapModule(AppModule);
declare var android;
application.android.on(application.AndroidApplication.activityCreatedEvent, (event) => {
const activity = event.activity;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
activity.getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
activity.getWindow().setStatusBarColor(android.graphics.Color.TRANSPARENT);
activity.getWindow().setNavigationBarColor(android.graphics.Color.TRANSPARENT);
} else {
activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
activity.getWindow().setNavigationBarColor(android.graphics.Color.TRANSPARENT);
}
const parent = activity.findViewById(android.R.id.content);
for (let i = 0; i < parent.getChildCount(); i++) {
const childView = parent.getChildAt(i);
if (childView instanceof android.view.ViewGroup) {
childView.setFitsSystemWindows(true);
childView.setClipToPadding(true);
}
}
});
Then to add transparency to the navbar, I followed this and I add this to line 24 of the main.ts file above. activity.getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
Now mind you there are also the styles.xml files we have to respect, so my styles.xml file (App_Resources\Android\src\main\res\values\styles.xml) looks like this:
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- theme to use FOR launch screen-->
<style name="LaunchScreenThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
<item name="toolbarStyle">@style/NativeScriptToolbarStyle</item>
<item name="colorPrimary">@color/ns_primary</item>
<item name="colorPrimaryDark">@color/ns_primaryDark</item>
<item name="colorAccent">@color/ns_accent</item>
<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:statusBarColor">@color/transparent</item>
</style>
<style name="LaunchScreenTheme" parent="LaunchScreenThemeBase"></style>
<!-- theme to use AFTER launch screen is loaded-->
<style name="AppThemeBase" parent="Theme.AppCompat.Light.NoActionBar">
<item name="toolbarStyle">@style/NativeScriptToolbarStyle</item>
<item name="colorPrimary">@color/ns_primary</item>
<item name="colorPrimaryDark">@color/ns_primaryDark</item>
<item name="colorAccent">@color/ns_accent</item>
<item name="android:statusBarColor">@color/transparent</item>
<item name="android:navigationBarColor">@color/transparent</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:windowTranslucentNavigation">false</item>
</style>
<style name="AppTheme" parent="AppThemeBase"></style>
<!-- theme for action-bar -->
<style name="NativeScriptToolbarStyleBase" parent="Widget.AppCompat.Toolbar">
<item name="android:background">@color/transparent</item>
<item name="theme">@color/transparent</item>
<item name="popupTheme">@color/transparent</item>
</style>
<style name="NativeScriptToolbarStyle" parent="NativeScriptToolbarStyleBase"></style>
Took me about 2-3 days to figure out, hope this helps
Upvotes: 0
Reputation: 14489
You can achieve the same effect programmatically on KitKat and afterward by setting the FLAG_LAYOUT_NO_LIMITS
flag inside the Window
.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow(); // in Activity's onCreate() for instance
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
If you set a background resource (like a color or a picture) to your layout, you will see the color or picture "below" the status bar.
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/primary_dark</item>
It looks like android:windowTranslucentStatus
and android:windowTranslucentNavigation
should be true
instead of false
<resources>
<style name="Theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
</style>
</resources>
Also, your transparent activity / container layout needs this property set:
android:fitsSystemWindows="true"
[Source][1] [1]: https://stackoverflow.com/a/29311321/1549700
Upvotes: 163
Reputation: 213
For API 29 and above use
<style name="Your.Theme">
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:enforceNavigationBarContrast">false</item>
</style>
Upvotes: 18
Reputation: 2406
You can use this kotlin extension function it will set status bar fully transparent (on API 23+, View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
flag available on API 23+) and navigation bar (on API 27+, View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
flag available on API 27+) otherwise it will use the systemUiScrim
color on API 21+
fun Activity.transparentStatusAndNavigation(
systemUiScrim: Int = Color.parseColor("#40000000") // 25% black
) {
var systemUiVisibility = 0
// Use a dark scrim by default since light status is API 23+
var statusBarColor = systemUiScrim
// Use a dark scrim by default since light nav bar is API 27+
var navigationBarColor = systemUiScrim
val winParams = window.attributes
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
statusBarColor = Color.TRANSPARENT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
navigationBarColor = Color.TRANSPARENT
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
systemUiVisibility = systemUiVisibility or
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
window.decorView.systemUiVisibility = systemUiVisibility
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
winParams.flags = winParams.flags or
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
winParams.flags = winParams.flags and
(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION).inv()
window.statusBarColor = statusBarColor
window.navigationBarColor = navigationBarColor
}
window.attributes = winParams
}
Upvotes: 16
Reputation: 4644
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initStatusNavBar();
transparentStatusAndNavigation();
showSystemUI();
// hideSystemUI();
}
public static void transparentStatusAndNavigation(Activity activity) {
Window window = activity.getWindow();
// make full transparent statusBar
if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
setWindowFlag(window, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, true);
}
if (Build.VERSION.SDK_INT >= 19) {
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
visibility = visibility | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
window.getDecorView().setSystemUiVisibility(visibility);
}
if (Build.VERSION.SDK_INT >= 21) {
int windowManager = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
windowManager = windowManager | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
setWindowFlag(window, windowManager, false);
window.setStatusBarColor(Color.TRANSPARENT);
window.setNavigationBarColor(Color.TRANSPARENT);
}
}
private static void setWindowFlag(final int bits, boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
in activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">
<View
android:id="@+id/status_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/primaryColorLightThemeDarkTrans"
tools:layout_height="24dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<!--Write Code Here-->
</LinearLayout>
<View
android:id="@+id/nav_bg"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/navColorLightThemeTrans"
tools:layout_height="?actionBarSize" />
</LinearLayout>
in java code:
private void initStatusNavBar() {
int statusBarHeight = getStatusBarHeight(activity);
int navBarHeight = getNavigationBarHeight(activity, statusBarHeight);
View statusBarBackground = findViewById(R.id.status_bg);
statusBarBackground.getLayoutParams().height = statusBarHeight;
View navBarBackground = findViewById(R.id.nav_bg);
if (Build.VERSION.SDK_INT >= 21) {
setNavigationBarHeight(activity, navBarBackground);
} else {
navBarBackground.getLayoutParams().height = navBarHeight;
}
}
public static int getStatusBarHeight(Activity activity) {
final Resources resources = activity.getResources();
final int resId = resources.getIdentifier("status_bar_height", "dimen", "android");
if (resId > 0) {
return resources.getDimensionPixelSize(resId);
}
return 0;
}
public static int getNavigationBarHeight(Activity activity, int statusBarHeight) {
Point point = getNavigationBarSize(activity);
int height = point.y;
if (isNotchDisplay(statusBarHeight)) {
height = height - statusBarHeight;
}
return height;
}
private static Point getNavigationBarSize(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Point appUsableSize = getAppUsableScreenSize(context);
Point realScreenSize = getRealScreenSize(context);
// navigation bar on the right
if (appUsableSize.x < realScreenSize.x) {
return new Point(realScreenSize.x - appUsableSize.x, appUsableSize.y);
}
// navigation bar at the bottom
if (appUsableSize.y < realScreenSize.y) {
return new Point(appUsableSize.x, realScreenSize.y - appUsableSize.y);
}
// navigation bar is not present
return new Point();
}
return new Point();
}
private static Point getAppUsableScreenSize(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point size = new Point();
if (null != windowManager) {
Display display = windowManager.getDefaultDisplay();
display.getSize(size);
}
return size;
}
private static Point getRealScreenSize(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point size = new Point();
if (null != windowManager) {
Display display = windowManager.getDefaultDisplay();
if (Build.VERSION.SDK_INT >= 17) {
display.getRealSize(size);
} else {
try {
size.x = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
size.y = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
return size;
}
private static boolean isNotchDisplay(int statusBarHeight) {
int normalStatusBarHeight = dpToPxForNav(25);
return statusBarHeight > normalStatusBarHeight;
}
private static int dpToPxForNav(float dp) {
DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
float px = dp * (metrics.densityDpi / 160f);
return Math.round(px);
}
public static void setNavigationBarHeight(Activity activity, View navBarBackground) {
ViewCompat.setOnApplyWindowInsetsListener(navBarBackground, (v, insets) -> {
int navBarHeight = insets.getSystemWindowInsetBottom();
navBarBackground.getLayoutParams().height = navBarHeight;
return insets.consumeSystemWindowInsets();
});
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void showSystemUI() {
statusBarBackground.setVisibility(View.VISIBLE);
navBarBackground.setVisibility(View.VISIBLE);
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public void hideSystemUI() {
statusBarBackground.setVisibility(View.GONE);
navBarBackground.setVisibility(View.GONE);
mDecorView.setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
}
<style name="MyAppTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
<!--For Notch Issues-->
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="o_mr1">shortEdges</item>
<item name="windowActionBarOverlay">true</item>
<item name="colorPrimary">@color/primaryColor</item>
<item name="colorPrimaryDark">@color/primaryColorDark</item>
<item name="colorAccent">@color/accentColor</item>
<item name="colorControlHighlight">@color/colorHighlight</item>
<item name="android:windowBackground">@android:color/white</item>
<item name="android:textColorPrimary">#fff6d7</item>
<item name="android:colorPrimary" tools:targetApi="lollipop">@color/primaryColor</item>
<item name="android:colorPrimaryDark" tools:targetApi="lollipop">@color/primaryColorDark</item>
<item name="android:statusBarColor" tools:targetApi="lollipop">@color/primaryColorDark</item>
<item name="android:colorAccent" tools:targetApi="lollipop">@color/accentColorLight</item>
<item name="android:colorControlHighlight" tools:targetApi="lollipop">@color/colorHighlight</item>
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/navColor</item>
<item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowTranslucentNavigation" tools:targetApi="kitkat">true</item>
</style>
<activity
android:name="com.MyActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="fullSensor"
android:theme="@style/MyAppTheme" />
Upvotes: 4
Reputation: 1281
You can also change the alpha of your colorPrimary and colorPrimaryDark to 00 and then add this to your onCreateMethod:
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
and also add this to your activity:
android:fitsSystemWindows="true"
Upvotes: 0
Reputation: 904
To draw your layout under statusbar :
values/styles.xml
<item name="android:windowTranslucentStatus">true</item>
values-v21/styles.xml
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/colorPrimaryDark</item>
Use CoordinatorLayout/DrawerLayout which already take care of the fitsSystemWindows parameter or create your own layout to like this:
public class FitsSystemWindowConstraintLayout extends ConstraintLayout {
private Drawable mStatusBarBackground;
private boolean mDrawStatusBarBackground;
private WindowInsetsCompat mLastInsets;
private Map<View, int[]> childsMargins = new HashMap<>();
public FitsSystemWindowConstraintLayout(Context context) {
this(context, null);
}
public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FitsSystemWindowConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (ViewCompat.getFitsSystemWindows(this)) {
ViewCompat.setOnApplyWindowInsetsListener(this, new android.support.v4.view.OnApplyWindowInsetsListener() {
@Override
public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {
FitsSystemWindowConstraintLayout layout = (FitsSystemWindowConstraintLayout) view;
layout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0);
return insets.consumeSystemWindowInsets();
}
});
setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
TypedArray typedArray = context.obtainStyledAttributes(new int[]{android.R.attr.colorPrimaryDark});
try {
mStatusBarBackground = typedArray.getDrawable(0);
} finally {
typedArray.recycle();
}
} else {
mStatusBarBackground = null;
}
}
public void setChildInsets(WindowInsetsCompat insets, boolean draw) {
mLastInsets = insets;
mDrawStatusBarBackground = draw;
setWillNotDraw(!draw && getBackground() == null);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
if (ViewCompat.getFitsSystemWindows(this)) {
ConstraintLayout.LayoutParams layoutParams = (ConstraintLayout.LayoutParams) child.getLayoutParams();
if (ViewCompat.getFitsSystemWindows(child)) {
ViewCompat.dispatchApplyWindowInsets(child, insets);
} else {
int[] childMargins = childsMargins.get(child);
if (childMargins == null) {
childMargins = new int[]{layoutParams.leftMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin};
childsMargins.put(child, childMargins);
}
if (layoutParams.leftToLeft == LayoutParams.PARENT_ID) {
layoutParams.leftMargin = childMargins[0] + insets.getSystemWindowInsetLeft();
}
if (layoutParams.topToTop == LayoutParams.PARENT_ID) {
layoutParams.topMargin = childMargins[1] + insets.getSystemWindowInsetTop();
}
if (layoutParams.rightToRight == LayoutParams.PARENT_ID) {
layoutParams.rightMargin = childMargins[2] + insets.getSystemWindowInsetRight();
}
if (layoutParams.bottomToBottom == LayoutParams.PARENT_ID) {
layoutParams.bottomMargin = childMargins[3] + insets.getSystemWindowInsetBottom();
}
}
}
}
}
requestLayout();
}
public void setStatusBarBackground(Drawable bg) {
mStatusBarBackground = bg;
invalidate();
}
public Drawable getStatusBarBackgroundDrawable() {
return mStatusBarBackground;
}
public void setStatusBarBackground(int resId) {
mStatusBarBackground = resId != 0 ? ContextCompat.getDrawable(getContext(), resId) : null;
invalidate();
}
public void setStatusBarBackgroundColor(@ColorInt int color) {
mStatusBarBackground = new ColorDrawable(color);
invalidate();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawStatusBarBackground && mStatusBarBackground != null) {
int inset = mLastInsets != null ? mLastInsets.getSystemWindowInsetTop() : 0;
if (inset > 0) {
mStatusBarBackground.setBounds(0, 0, getWidth(), inset);
mStatusBarBackground.draw(canvas);
}
}
}
}
main_activity.xml
<FitsSystemWindowConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ImageView
android:layout_width="0dp"
android:layout_height="0dp"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/toolbar_background"
app:layout_constraintBottom_toBottomOf="@id/toolbar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="@android:color/transparent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Content"
android:textSize="48sp" />
</LinearLayout>
</FitsSystemWindowConstraintLayout>
Result :
Upvotes: 1
Reputation: 3252
For those who want a completely transparent status bar and navigation bar on KitKat and up there is a small conflict with using windowTranslucentNavigation
with @Machado answer's for Lollipop and to prevent that conflict separate the styles
styles.xml
<style name="LockScreenStyle" parent="@android:style/Theme.Wallpaper.NoTitleBar">
<item name="android:windowTranslucentStatus" tools:targetApi="kitkat">true</item>
<item name="android:windowTranslucentNavigation" tools:targetApi="kitkat">true</item>
</style>
styles.xml (v21)
<style name="LockScreenStyle" parent="@android:style/Theme.Wallpaper.NoTitleBar">
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
MyClass.java
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window w = getWindow(); // in Activity's onCreate() for instance
w.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
w.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
}
}
Upvotes: 0
Reputation: 3098
I use this since it keeps the height of the status bar and nav bar
<!-- Base application theme. -->
<style name="theme" parent="android:Theme.Material.Wallpaper.NoTitleBar">
<item name="android:navigationBarColor">#00000000</item>
<item name="android:statusBarColor">#00000000</item>
</style>
This does require API 21+ however
Upvotes: 9
Reputation: 6449
You need to add android:windowDrawsSystemBarBackgrounds
flag to you theme
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
Or call this in onCreate()
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
Upvotes: 4
Reputation: 3193
The following code is an example of what I use in my project:
styles.xml
<style name="FadingActionBarTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:actionBarStyle">@style/FadingActionBarWidget</item>
</style>
<style name="FadingActionBarWidget.Transparent">
<item name="android:background">@android:color/transparent</item>
</style>
<style name="FadingActionBarTheme.TranslucentActionBar">
<item name="android:icon">@drawable/ic_ab_icon</item>
<item name="android:actionBarStyle">@style/FadingActionBarWidget.Transparent</item>
<item name="android:windowActionBarOverlay">true</item>
<item name="android:windowContentOverlay">@null</item>
</style>
AndroidManifest.xml
<activity
android:name=".MyActivity"
android:label="@string/app_name"
android:theme="@style/FadingActionBarTheme.TranslucentActionBar">
</activity>
Upvotes: 4