Barra de estado de Android M Light y Dark mediante programación: ¿cómo volverlo a oscurecer?
user-interface android-6.0-marshmallow (6)
En el Android M tenemos la capacidad de hacer que los iconos de la barra de estado estén oscuros. Para ello podemos especificar el atributo en el xml del tema:
<item name="android:windowLightStatusBar">true</item>
O lo podemos configurar en tiempo de ejecución con este código:
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);
}
Y en realidad funciona bien. ¿Pero la pregunta es cómo configurar correctamente un modo de barra de estado como oscuro en el tiempo de ejecución?
Ya probé esas variantes:
// 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);
Entonces, ¿cómo se puede hacer de una manera correcta?
Basado en la respuesta de @phan-van-linh, escribí esta clase para Android Xamarin
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
}
}
La solución publicada por @Aracem es válida, pero no funciona si intenta cambiar también el color de fondo de la barra de estado. En mi caso lo hago de la siguiente manera.
Para habilitar windowLightStatusBar (por ejemplo, dentro de una clase de Utils):
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);
}
}
Para restaurar a StatusBar al estado anterior:
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));
}
}
Restaurar el color de la barra de estado es suficiente, también restaura los colores de los iconos. MUY IMPORTANTE: la operación de restauración no se producirá hasta que la vista utilizada en setLightStatusBar (Vista vista ..) desaparezca (es decir, view.getVisibility () == GONE | INVISIBLE) de la pantalla.
Me baso en @Aracem y @Carlos Hernández Gil, pero creo que será fácil de entender si usamos XOR en modo bit (operador ^ en 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
}
}
Explique
Primero, mire SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
y 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;
...
}
}
Creo que el código de 2 líneas a continuación es bastante difícil de entender
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
A primera vista, creo que podemos usar simples como
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)
Pero debemos usar |
y ^
porque
Por ejemplo, queremos configurar tanto la barra de estado como la barra de navegación, luego usaremos
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
Cuando no queremos que la barra de estado sea más liviana, podemos usar
flags = View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
O
flags = activity.getWindow().getDecorView().getSystemUiVisibility();
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
Para saber más por qué usamos |
y ^
, creo que el siguiente tutorial puede ayudar https://medium.com/@JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1 Aquí está mi comprensión. Espero que esto ayude
Reuní este sencillo objeto de utilidad que le permite cambiar el color de la barra de estado y la barra de estado de la luz de encendido / apagado para cualquier fragmento. Sin embargo, esto se basa en el uso del componente de navegación de Android Jetpack para la navegación (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
}
}
}
}
}
Para usar esto, llame a lo siguiente desde onViewCreated
cualquier fragmento:
StatusBarUtil.changeStatusBarColor(requireActivity(), someDarkColor, false)
Según el proyecto de Nick Butcher "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);
}
}
Puedes encontrar el proyecto Here
Voy a hacer algunos cambios en las respuestas anteriores.
hacer una clase
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);
}
}
}
y llámalo donde quieras así
Window window = getWindow();
View view = window.getDecorView();
DarkStatusBar.setLightStatusBar(view,this);