Android M Light и Dark status bar программно - как сделать его темным снова?
В Android M у нас есть возможность сделать иконки в строке состояния темными. Для этого мы можем указать атрибут в теме xml:
<item name="android:windowLightStatusBar">true</item>
ИЛИ мы можем установить его во время выполнения с помощью этого кода:
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);
}
И это на самом деле работает нормально. Но вопрос в том, как правильно установить режим строки состояния на темный во время выполнения?
Я уже попробовал эти варианты:
// 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);
Так как же это сделать правильно?
Ответы
Ответ 1
Решение, отправленное @Aracem, действительно, но не работает, если вы попытаетесь изменить цвет фона в строке состояния. В моем случае я делаю это следующим образом.
Чтобы включить windowLightStatusBar (программно, например, в классе 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);
}
}
Чтобы восстановить статусBar в предыдущем состоянии:
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));
}
}
Восстановление цвета строки состояния достаточно, оно также восстанавливает цвета значков. ОЧЕНЬ ВАЖНО: операция восстановления не будет выполняться до тех пор, пока вид, используемый в setLightStatusBar (View view..), не исчезнет (т.е. view.getVisibility() == GONE | INVISIBLE) с экрана.
Ответ 2
Согласно проекту Ник Батчер "Плед"
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);
}
}
Вы можете найти проект здесь
Ответ 3
Я основываюсь на @Aracem и @Carlos Hernández Gil, но я думаю, что это будет легко понять, если мы будем использовать побитовый XOR (оператор ^ в 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
}
}
объяснять
Во- первых, посмотрите на SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
и 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;
...
}
}
Я думаю, что код из 2 строк ниже довольно сложно понять
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
На первый взгляд, я просто думаю, что мы можем использовать простые как
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)
Но мы должны использовать |
и ^
потому что
Например, мы хотим, чтобы строка состояния и панель навигации светились, тогда мы будем использовать
flags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR | View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
Когда мы не хотим, чтобы строка состояния светилась больше, мы можем использовать
flags = View.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
ИЛИ ЖЕ
flags = activity.getWindow().getDecorView().getSystemUiVisibility();
flags = flags ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
activity.getWindow().getDecorView().setSystemUiVisibility(flags);
Чтобы узнать больше, почему мы используем |
и ^
, я думаю, что учебник ниже может помочь https://medium.com/@JakobUlbrich/flag-attributes-in-android-how-to-use-them-ac4ec8aee7d1 Вот мое понимание. Надеюсь это поможет
Ответ 4
Я собрал этот простой объект утилиты, который позволяет включать/выключать цвет строки состояния и строки состояния света в любом фрагменте. Однако это зависит от использования компонента Android Jetpack 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
}
}
}
}
}
Чтобы использовать это, вызовите следующее из любого фрагмента onViewCreated
:
StatusBarUtil.changeStatusBarColor(requireActivity(), someDarkColor, false)
Ответ 5
я сделаю некоторые изменения в приведенных выше ответах.
сделать класс
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);
}
}
}
и назовите его везде, где хотите.
Window window = getWindow();
View view = window.getDecorView();
DarkStatusBar.setLightStatusBar(view,this);
Ответ 6
Основываясь на ответе @phan-van-linh, я написал этот класс для 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
}
}