White Status Bar in dark mode - android

Is it possible to make white status bar programmatically in dark mode? (Application is based on single Activity, and I have to make this only for one fragment)
also app should based on Theme.MaterialComponents.Light.NoActionBar to have no bad effect on other styles.
I've tried to set white color and ui visibility to light mode, but it seems force dark is applied to status bar background automatically.
the code looks like this:
var flags = it.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
window.decorView.systemUiVisibility = flags
//it is #F0F0F0 in white and night sources
var statusBarColor = context.getColorCompat(R.color.white)
window?.statusBarColor = statusBarColor
but only systemUiVisibility flag applies:

Add this to Util file
private val insetsController: WindowInsetsControllerCompat? by lazy {
activity?.window?.decorView?.let(ViewCompat::getWindowInsetsController)
}
private fun setLightStatusBar(light: Boolean) {
insetsController?.isAppearanceLightStatusBars = light
}
Hope it will solve your issue.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.BLUE);
}
and an other way is to create 2 themes class and define specific color for status bar.

ok, answer was in the question... but I haven't think to try to disable force dark before...
as I've mentioned as Theme.MaterialComponents.Light.NoActionBar been used I have to disable forceDark.
so the solution in this case looks like:
val decorView = window.decorView
val wic = WindowInsetsControllerCompat(window, decorView)
wic.isAppearanceLightStatusBars = true
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
//disable force dark for Light theme
window.decorView.isForceDarkAllowed = false
}
window.statusBarColor = Color.WHITE

Related

How to set the status bar color in the whole device to green as the default phone app does?

I'm making an app that can place and receive VoIP voice calls. As I want to mimic the default phone behavior, I want to do the same the system does when having a phone call: painting the status bar green while having a call, to highlight the user that he's on a call.
Just to clarify to avoid being marked as duplicated: this question is related to changing the status bar color not just in our Activity but in the whole device, as some phones when in a call.
Is it possible to achieve it?
Use something like this this (for versions > 23)
This is my old method. Some things are deprecated, find a solution and fix it
protected void setStatusBarColor(View view, int color, boolean isLight) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(color == 0) color = ContextCompat.getColor(this, R.color.colorPrimaryDark);
if(isLight) {
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
}
//getWindow().setStatusBarColor(Color.WHITE);
Window window = getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(color);
}
}

Change StatusBar color and show ActionMode at the same time

I change status bar color whenever action mode is shown using this piece of code:
override fun onActionModeStarted(mode: ActionMode?) {
super.onActionModeStarted(mode)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window?.statusBarColor = colorBlue
}
}
The problem is action mode shows up with an animation while window.statusBarColo = changes status bar color immediately and as a result status bar color is changed a little bit sooner than action mode being displayed and it is so unpleasant to see. Do you guys have any solution for this?

How to set light status bar for Android N

I use this way to set light status bar for Android M, and it works well:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
But, it does not work at Android N. The words in status bar are still white. Is it a bug? Or is there any way to set light status bar at Android N?
Well, I found the question.It did works to set light status bar mode.But after that, i changed the status bar's color, called setSystemUiVisibility() again and set other value.So the light status bar is not valid.
Just call this method from any activity and pass color code too
public static void makeStatusBarLight(Activity activity, int color) {
Window window = activity.getWindow();
window.addFlags(FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(FLAG_TRANSLUCENT_STATUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(color);
}
activity.getWindow().getDecorView().setSystemUiVisibility(
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
}
call like this
makeStatusBarLight(BaseActivity.this, getResources().getColor(R.color.yourcolor));

Android M Light and Dark status bar programmatically - how to make it dark again?

In the Android M we have ability to make status bar icons dark. To do that we can specify attribute in the theme's xml:
<item name="android:windowLightStatusBar">true</item>
OR we cat set it at runtime with this code:
View someView = findViewById(R.id.some_view);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
someView.setSystemUiVisibility(someView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
And it actually works fine. But question is how to properly set a status bar mode to dark at runtime?
I already tried these variants:
// Makes status bar mode dark, but also hides it along with all navigation views.
someView.setSystemUiVisibility(someView.getSystemUiVisibility() | ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
// Does nothing
someView.setSystemUiVisibility(someView.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
// Also does nothing
someView.setSystemUiVisibility(someView.getSystemUiVisibility() ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
So how it can be done the right way?
The solution posted by #Aracem is valid but, doesn't work if you try change also the background color of the status bar. In my case I do it in the following way.
To enable windowLightStatusBar(programatically,inside a Utils class for example):
public static void setLightStatusBar(View view,Activity activity){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.WHITE);
}
}
To restore to StatusBar to the previous state:
public static void clearLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Window window = activity.getWindow();
window.setStatusBarColor(ContextCompat
.getColor(activity,R.color.colorPrimaryDark));
}
}
Restoring the color of the status bar is enough, it restores also the icons colors.
VERY IMPORTANT: The restore operation will not occur until the view used in setLightStatusBar(View view..) dissapears(that is, view.getVisibility()==GONE|INVISIBLE) from the screen.
According to Nick Butcher's project "Plaid"
public static void clearLightStatusBar(#NonNull View view) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
}
}
You can find this file here.
I base on #Aracem and #Carlos Hernández Gil but I think it will easy to understand if we use bitwise XOR (^ operator in Java)
private void setLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = activity.getWindow().getDecorView().getSystemUiVisibility(); // get current flag
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // add LIGHT_STATUS_BAR to flag
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.GRAY); // optional
}
}
private void clearLightStatusBar(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = activity.getWindow().getDecorView().getSystemUiVisibility(); // get current flag
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // use XOR here for remove LIGHT_STATUS_BAR from flags
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.GREEN); // optional
}
}
Explain
First, look at SYSTEM_UI_FLAG_LIGHT_STATUS_BAR and setSystemUiVisibility
/**
* Flag for {#link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that
* is compatible with light status bar backgrounds.
*/
public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000;
public void setSystemUiVisibility(int visibility) {
if (visibility != mSystemUiVisibility) {
mSystemUiVisibility = visibility;
...
}
}
I think 2 lines code below is quite hard to understand
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for set light status bar
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for clear light status bar
At first look, I just think we can use simple like
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; // for set light status bar
flags = 0; // for clear light status bar (0 <=> LIGHT_STATUS_BAR <=> default systemUiVisibility)
But we should use | and ^ because
Example, we want to set both status bar and navigationbar to light, then we will use
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
When we don't want status bar is light anymore, we can use
flags = View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
OR
flags = activity.getWindow().getDecorView().getSystemUiVisibility();
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
To know more why we use | and ^, I think the tutorial below may help
https://medium.com/#JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1
Here is my understand. Hope this help
The way I switched light and dark for APIs 23-30 was a little different than these. This is a kotlin version
Since I was using Compose with the Crossfade animation to change themes, in some cases would call this function twice, hence making xor undo itself. An alternative is an inverse or operation. My light theme switcher-thing ended up looking like this
#Suppress("DEPRECATION")
fun invertInsets(darkTheme: Boolean, window: Window) {
if (Build.VERSION.SDK_INT >= 30) {
//Correct way of doing things
val statusBar = APPEARANCE_LIGHT_STATUS_BARS
val navBar = APPEARANCE_LIGHT_NAVIGATION_BARS
if (!darkTheme) {
window.insetsController?.setSystemBarsAppearance(statusBar, statusBar)
window.insetsController?.setSystemBarsAppearance(navBar, navBar)
} else {
window.insetsController?.setSystemBarsAppearance(0, statusBar)
window.insetsController?.setSystemBarsAppearance(0, navBar)
}
} else {
// Does bitwise operations (or to add, inverse or to remove)
// This is depreciated but the new version is API 30+ so I should have this here
val flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR or
if (Build.VERSION.SDK_INT >= 26) View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR else 0
if (!darkTheme) {
window.decorView.systemUiVisibility =
window.decorView.systemUiVisibility or flags
} else {
window.decorView.systemUiVisibility =
(window.decorView.systemUiVisibility.inv() or flags).inv()
}
}
}
The bit for API 30+ is what's not depreciated, but realistically not many phones are at API 30 so there's also the bit for lower APIs
It just calculates flags (since setting LIGHT_NAVIGATION_BARS is API 26+) beforehand for conciseness and then either definitively sets or resets those exact flags. No and or xor funny buisiness. or will always set the flags to 1, and the inverse or thing will always set the flags to 0. This is only possible because both SYSTEM_UI_FLAG_LIGHT_STATUS_BAR and SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR are one bit, however. Otherwise it would probably need to use xor.
systemUiVisibility - is deprecated now. You can use WindowInsetsControllerCompat instead.
private val insetsController: WindowInsetsControllerCompat? by lazy {
activity?.window?.let { window -> WindowInsetsControllerCompat(window, window.decorView) }
}
private fun setLightStatusBar(light: Boolean) {
insetsController?.isAppearanceLightStatusBars = light
}
UPD:
Above constructor for WindowInsetsControllerCompat is deprecated, so use the following instantiation instead:
private val insetsController: WindowInsetsControllerCompat? by lazy {
activity?.window?.decorView?.let(ViewCompat::getWindowInsetsController)
}
There is a slight change in API 30 of the SDK and now the light status bar appearance is controlled by WindowInsetsController, which can be obtained from a Window.
Below is a sample method (within an Activity) in Kotlin, combining the new API with the previously used View.setSystemUiVisibility for older Android SDK versions. Bear in mind that this only changes the system icons appearance of the status bar and the actual color of the status bar can still be set by Window.setStatusBarColor.
#Suppress("DEPRECATION")
private fun setSystemUiLightStatusBar(isLightStatusBar: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val systemUiAppearance = if (isLightStatusBar) {
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
} else {
0
}
window.insetsController?.setSystemBarsAppearance(systemUiAppearance,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS)
} else {
val systemUiVisibilityFlags = if (isLightStatusBar) {
window.decorView.systemUiVisibility or SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
window.decorView.systemUiVisibility and SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
window.decorView.systemUiVisibility = systemUiVisibilityFlags
}
}
}
I put together this simple utility object that allows you to change status bar color and light status bar on/off for within any fragment. However, this relies on using the Android Jetpack Navigation component for navigation (Kotlin):
object StatusBarUtil {
fun changeStatusBarColor(activity: Activity, #ColorInt color: Int, lightStatusBar: Boolean) {
activity.window?.let { win ->
val nav = Navigation.findNavController(activity, R.id.your_nav_host_fragmen /* TODO: Use the ID of your nav host fragment */)
val currentDest = nav.currentDestination?.id
val oldColor = win.statusBarColor
val oldFlags = win.decorView.systemUiVisibility
win.statusBarColor = color
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var flags = oldFlags
flags = if (lightStatusBar) {
flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
} else {
flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
}
win.decorView.systemUiVisibility = flags
}
nav.addOnNavigatedListener { _, dest ->
if (dest.id != currentDest) {
win.statusBarColor = oldColor
win.decorView.systemUiVisibility = oldFlags
}
}
}
}
}
To use this, call the following from within any fragment's onViewCreated:
StatusBarUtil.changeStatusBarColor(requireActivity(), someDarkColor, false)
Based on #phan-van-linh answer, I wrote this class for Xamarin Android
public static class ActivityExtensions
{
public static void SetLightStatusBar(this Activity activity)
{
int flags = (int)activity.Window.DecorView.SystemUiVisibility; // get current flag
flags |= (int)SystemUiFlags.LightStatusBar; // add LIGHT_STATUS_BAR to flag
activity.Window.DecorView.SystemUiVisibility = (StatusBarVisibility)flags;
//activity.Window.SetStatusBarColor(Color.GRAY); // optional
}
public static void ClearLightStatusBar(this Activity activity)
{
int flags = (int)activity.Window.DecorView.SystemUiVisibility; // get current flag
flags = flags ^ (int)SystemUiFlags.LightStatusBar; // use XOR here for remove LIGHT_STATUS_BAR from flags
activity.Window.DecorView.SystemUiVisibility = (StatusBarVisibility)flags;
//activity.Window.setStatusBarColor(Color.GREEN); // optional
}
}
To change to light status bar use:-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
activity?.window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
To change back to dark status bar :-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
activity?.window?.decorView?.systemUiVisibility = 0
i will make some changes in above answers.
make a class
public class DarkStatusBar {
public static void setLightStatusBar(View view, Activity activity){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int flags = view.getSystemUiVisibility();
flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
view.setSystemUiVisibility(flags);
activity.getWindow().setStatusBarColor(Color.WHITE);
}
}
}
and Call it wherever you want like this
Window window = getWindow();
View view = window.getDecorView();
DarkStatusBar.setLightStatusBar(view,this);
It works for me
fun Activity.clearLightStatusBar() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val window = window
window.statusBarColor = ContextCompat
.getColor(this, R.color.ultramarine_blue)
}
}
Set blue background status bar with light text color kotlin version
fun setBlueStatusBarColor(window: Window, context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
window.statusBarColor = context.getColor(R.color.colorBlue)
}else {
window.statusBarColor = context.resources.getColor(R.color.colorBlue)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
var flags: Int = window.decorView.systemUiVisibility
flags = flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
window.decorView.systemUiVisibility = flags
}
}
}
/**
* Changes color of the status bar icons
* #param isLight if true - shows dark icons, light else
*/
fun setStatusBarUiTheme(activity: Activity?, isLight: Boolean) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activity?.window?.decorView?.let {
it.systemUiVisibility = if (isLight)
it.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR // dark icons
else
it.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() // light icons
}
}
}
In res/styles.xml
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowLightStatusBar">true</item>
.......
</style>
<style name="AppTheme.DarkStatus" parent="AppTheme" tools:targetApi="23" >
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor" >#color/status_bar_color</item>
</style>
In code
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme_DarkStatus); //To set DarkStatusBar theme
setContentView(R.layout.activity_drawer);
....
}
For people who doesn't have a Window instance. It's also possible to do with a View instance (For API 30) :
fun setLightStatusBar(view: View) = view.windowInsetsController?.setSystemBarsAppearance(
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)
fun clearLightStatusBar(view: View) = view.windowInsetsController?.setSystemBarsAppearance(
0,
WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
)

Set status bar color dynamically in android

How to set status bar color dynamically for an application, am using view pager while swiping (horizontally) status bar color and title bar and button should change the color . as per my code title and button color changing perfectly ,but the issue is status bar color taking next color from array list. how to fix that issue can anyone help me. here is my code
private int[] colors = new int[]{0xffffd200, 0xff37beb7, 0xff00ccff, 0xff8585c1, 0xfff2a03c, 0xff2a80b9, 0xfff15972,
0xffe9776c, 0xff9dcc96,0xff76c069};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = ((Activity) context).getWindow();
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
int coloring = position % colors.length;
int new_color = colors[coloring];
window.setStatusBarColor(new_color);
title_bar.setBackgroundColor(new_color);
set_share.setBackgroundColor(new_color);
}
else{
int color = position % colors.length;
itemView.setBackgroundColor(colors[color]);
title_bar.setBackgroundColor(colors[color]);
set_share.setBackgroundColor(colors[color]);
}
To change status bar color use setStatusBarColor(int color). According the javadoc, we also need set some flags on the window.
Working snippet of code:
Window window = activity.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(activity.getResources().getColor(R.color.example_color));
This is taken from following reference:
How to change status bar color to match app in Lollipop? [Android]
coming to Status bar color, you can only add it to devices with API level more than 21. To those devices which satisfy this condition you can change the StatusBar color dynamically as shown below.
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.setStatusBarColor(getResources().getColor(R.color.Statusbar));
}
When I wanted to set the status bar color, I used https://github.com/jgilfelt/SystemBarTint
I used it like that :
public static void colorStatusBar(Window window, Activity activity) {
Log.v(Constants.LOG_TAG, "Start defining color bar status");
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
SystemBarTintManager tintManager = new SystemBarTintManager(activity);
tintManager.setStatusBarTintEnabled(true);
tintManager.setTintColor(activity.getResources().getColor(R.color.colorPrimaryDark));
}
}
But beware that setting status bar color is only possible if your app runs on a phone with API >= 19

Categories

Resources