Change Status Bar Color with Appcompat Actionbaractivity

Change status bar color with AppCompat ActionBarActivity

I'm not sure I understand the problem.

I you want to change the status bar color programmatically (and provided the device has Android 5.0) then you can use Window.setStatusBarColor(). It shouldn't make a difference whether the activity is derived from Activity or ActionBarActivity.

Just try doing:

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);
}

Just tested this with ActionBarActivity and it works alright.


Note: Setting the FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag programmatically is not necessary if your values-v21 styles file has it set already, via:

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

How to change Action Bar and Status Bar color in activity?

if I understand correctly you want to change from java code .. When you call an if try to use this method:

import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

changeColor(R.color.red);
}

public void changeColor(int resourseColor) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(ContextCompat.getColor(getApplicationContext(), resourseColor));
}

ActionBar bar = getSupportActionBar();
bar.setBackgroundDrawable(new ColorDrawable(getResources().getColor(resourseColor)));

}

}

How to change status bar color on entering contextual action mode

There are two requests when the contextual action bar (CAB) is show/hidden:

  1. Toggle status bar icon light mode.
  2. Synchronize the color animation between the CAB & the status bar.

Sync color animation between CAB & status bar

You can animate the change of the status bar color using ArgbEvaluator with an adjusted duration that tends to the CAB duration (with trial and error it's near 300 msec; I have no documentation clue for the exact value, but you can adjust that to your needs):

fun switchStatusColor(colorFrom: Int, colorTo: Int, duration: Long) {
val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
colorAnimation.duration = duration // milliseconds

colorAnimation.addUpdateListener { animator ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
window.statusBarColor = animator.animatedValue as Int
}
colorAnimation.start()
}

And this need to be called with the appropriate colors within onCreateActionMode & onDestroyActionMode:

val callback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menuInflater.inflate(R.menu.contextual_action_bar, menu)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switchStatusColor(
window.statusBarColor,
ContextCompat.getColor(this@MainActivity, R.color.grey_100), 300
)

}

return true
}

override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}

override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return false
}

override fun onDestroyActionMode(mode: ActionMode?) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switchStatusColor(
window.statusBarColor,
ContextCompat.getColor(this@MainActivity, R.color.white), 300
)
}

}

}

Toggle status bar icon light mode

For API level below 30 (Android R), use systemUiVisibility, and WindowInsetsController for API level 30 and above:

For some reason the WindowInsetsController didn't work for me, even by using the below 4 versions, but thankfully the old flag works, so I kept it in API level > 30:

private fun switchStatusBarIconLight(isLight: Boolean) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.setSystemBarsAppearance(
if (isLight) APPEARANCE_LIGHT_STATUS_BARS else 0,
APPEARANCE_LIGHT_STATUS_BARS
)

WindowInsetsControllerCompat(
window,
window.decorView
).isAppearanceLightStatusBars =
isLight

ViewCompat.getWindowInsetsController(window.decorView)?.apply {
isAppearanceLightStatusBars = isLight
}

WindowCompat.getInsetsController(
window,
window.decorView
)?.isAppearanceLightStatusBars = isLight

window.decorView.systemUiVisibility =
if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else 0 // Deprecated in API level 30 // but only works than the above

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else 0 // Deprecated in API level 30
}

}

So, the working demo:

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

// Setting up the status bar when the app starts
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
window.statusBarColor = ContextCompat.getColor(this@MainActivity, R.color.white)
switchStatusBarIconLight(true)


val callback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {
menuInflater.inflate(R.menu.contextual_action_bar, menu)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switchStatusColor(
window.statusBarColor,
ContextCompat.getColor(this@MainActivity, R.color.grey_100), 300
)
}

switchStatusBarIconLight(false)

return true
}

override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}

override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return false
}

override fun onDestroyActionMode(mode: ActionMode?) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
switchStatusColor(
window.statusBarColor,
ContextCompat.getColor(this@MainActivity, R.color.white), 300
)
}

switchStatusBarIconLight(true)

}

}
}

*
* Animate switching the color of the status bar from the colorFrom color to the colorTo color
* duration: animation duration.
* */
private fun switchStatusColor(colorFrom: Int, colorTo: Int, duration: Long) {
val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
colorAnimation.duration = duration // milliseconds

colorAnimation.addUpdateListener { animator ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
window.statusBarColor = animator.animatedValue as Int
}
colorAnimation.start()
}


/*
* Switch the dark mode of the status bar icons
* When isLight is true, the status bar icons will turn light
* */
private fun switchStatusBarIconLight(isLight: Boolean) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.setSystemBarsAppearance(
if (isLight) APPEARANCE_LIGHT_STATUS_BARS else 0,
APPEARANCE_LIGHT_STATUS_BARS
)
WindowInsetsControllerCompat(
window,
window.decorView
).isAppearanceLightStatusBars =
isLight

ViewCompat.getWindowInsetsController(window.decorView)?.apply {
isAppearanceLightStatusBars = isLight
}

WindowCompat.getInsetsController(
window,
window.decorView
)?.isAppearanceLightStatusBars = isLight

window.decorView.systemUiVisibility =
if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else 0 // Deprecated in API level 30 // but only works than the above

} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (isLight) View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR else 0 // Deprecated in API level 30
}

}

}

Preview:

Sample Image

UPDATE

Another approach

Instead of animating the status bar to sync with the CAB, you can instead disable the animation. But this requires you to use a customView to the CAB instead of a menu.

There are two places to do that:

  • When the CAB is shown

    Do it whenever you call startSupportActionMode:

val mode = startSupportActionMode(callback)
ViewCompat.animate(mode?.customView?.parent as View).alpha(0f)
  • When the CAB is hidden:

    Do it in onDestroyActionMode

override fun onDestroyActionMode(mode: ActionMode?) {
// Hiding the CAB
(mode?.customView?.parent as View).visibility = View.GONE
}

The downside is that no animation anymore, and there is a delay to show the CAB because it is just hidden using the alpha, so the animation is still consumed but invisible because of setting the alph. And this requires you to to toggle the status bar color after some delay which is assumed by 300 millisec in the first approach:

val callback = object : ActionMode.Callback {
override fun onCreateActionMode(mode: ActionMode?, menu: Menu?): Boolean {

val customView: View = LayoutInflater.from(this@MainActivity).inflate(
R.layout.custom_contextual_action_bar, null
)
mode?.customView = customView

Handler(Looper.getMainLooper()).postDelayed({
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor =
ContextCompat.getColor(this@MainActivity, R.color.grey_100)
switchStatusBarIconLight(false)
}
}, 300)

return true
}

override fun onPrepareActionMode(mode: ActionMode?, menu: Menu?): Boolean {
return false
}

override fun onActionItemClicked(mode: ActionMode?, item: MenuItem?): Boolean {
return false
}

override fun onDestroyActionMode(mode: ActionMode?) {
// Hiding the CAB
(mode?.customView?.parent as View).visibility = View.GONE

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
window.statusBarColor =
ContextCompat.getColor(this@MainActivity, R.color.white)
switchStatusBarIconLight(true)
}

}

}

// Call:

val mode = startSupportActionMode(callback)
ViewCompat.animate(mode?.customView?.parent as View).alpha(0f)

Sample Image

Change status bar color on two different activities

You can define a second theme in your styles.xml:

<style name="AppTheme.Secondary">
<!-- set your attributes here -->
</style>

And then, in your AndroidManifest.xml, set your other activity to use the other theme:

<activity
android:name=".YourSecondActivity"
android:theme="@style/AppTheme.Secondary"/>

facing problem in changing status bar color in jetpack compose

In each activity, instead of using:

rememberSystemUiController().setStatusBarColor,

set the statusbar color like this:

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposePlaygroundTheme {
window?.setStatusBarColor(Color.Red.toArgb())
}
}
}
}


Related Topics



Leave a reply



Submit