Материал Android: цвет строки состояния не изменится

Я разрабатываю простое приложение для тестирования дизайна материалов. Я использую com.android.support:appcompat-v7:21.0.0, и моя активность выглядит следующим образом:

public class MyActivity extends ActionBarActivity {
   ...
}

Макет определяется как:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyActivity">

    <android.support.v7.widget.Toolbar
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="128dp"
        android:minHeight="?attr/actionBarSize"
        android:background="?attr/colorPrimaryDark"/>
</LinearLayout>

Теперь я определил свою тему следующими материальными рекомендациями:

<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
    <item name="colorPrimary">@color/colorPrimary500</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark700</item>
</style>

Я хотел бы изменить цвет строки состояния в пред Android 5 и установить его на colorPrimaryDark, но я не могу найти способ. Я попытался использовать:

getWindow().setStatusBarColor(..)

но цвет setStatusBar доступен с уровня 21. Почему, если я определяю colorPrimaryDark в своей теме и использую appcompact, строка состояния не меняет цвет? Кто может помочь?

Ответ 1

Строка состояния - системное окно, принадлежащее операционной системе. На устройствах до 5.0 для Android приложения не имеют права изменять свой цвет, поэтому это не то, что библиотека AppCompat может поддерживать для более старых версий платформы. Лучший AppCompat может обеспечить поддержку окраски ActionBar и других общих виджетах пользовательского интерфейса в приложении.

Ответ 2

Пока цвет строки состояния не поддерживается < 5.0, 4.4, вы можете использовать работу для достижения более темного цвета:

Сделать индикатор состояния полупрозрачным

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

Затем используйте панель инструментов AppCompat для вашей панели приложений, убедившись, что она подходит к системным окнам:

<android.support.v7.widget.Toolbar
    android:id="@+id/toolbar"
    ...
    android:fitsSystemWindows="true"/>

Обязательно установите панель инструментов в качестве панели действий:

protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ...
    toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

Панель инструментов растягивается под строкой состояния, а полупрозрачность строки состояния делает ее более темной вторичной. Если это не тот цвет, который вы хотите, эта комбинация позволяет вам подобрать представление под вашей статусной полосой, в зависимости от цвета фона по вашему выбору (хотя он по-прежнему тонирован по статусной строке).

Вид обходного граничного случая из-за только 4.4, но там вы идете.

Ответ 3

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
    getWindow().setStatusBarColor(getResources().getColor(R.color.actionbar));
}

Поместите этот код в свой метод Activity onCreate. Это помогло мне.

Ответ 4

Как уже отмечалось другими, это можно легко решить, добавив следующее к onCreate() Activity:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        getWindow().setStatusBarColor(ContextCompat.getColor(this, R.color.primary_dark));
    }

Однако важный момент, который я хочу добавить здесь, заключается в том, что в некоторых случаях даже вышеизложенное не меняет цвет строки состояния. Например, при использовании библиотеки MikePenz для навигационного ящика она неявно переопределяет цвет строки состояния, поэтому вам нужно вручную добавить для нее следующее:

.withStatusBarColorRes(R.color.status_bar_color)

Ответ 5

Раскраска строки состояния не поддерживается в AppCompat v7: 21.0.0.

Из сообщения блога разработчиков Android

На старых платформах AppCompat эмулирует цветную тематику, где это возможно. На данный момент это ограничивается окраской панели действий и некоторых виджетов.

Это означает, что в AppCompat lib будут отображаться только строки состояния на Lollipop и выше.

Ответ 6

Переключитесь на AppCompatActivity и добавьте 25 dp paddingTop на панели инструментов и включите

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

Затем панель инструментов will go up top the top

Ответ 7

Это решение задает цвет статусной панели Lollipop, Kitkat и некоторых устройств pre Lollipop (Samsung и Sony). SystemBarTintManager управляет устройствами Kitkat;)

@Override
protected void onCreate( Bundle savedInstanceState ) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    hackStatusBarColor(this, R.color.primary_dark);
}

@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
public static View hackStatusBarColor( final Activity act, final int colorResID ) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        try {

            if (act.getWindow() != null) {

                final ViewGroup vg = (ViewGroup) act.getWindow().getDecorView();
                if (vg.getParent() == null && applyColoredStatusBar(act, colorResID)) {
                    final View statusBar = new View(act);

                    vg.post(new Runnable() {
                        @Override
                        public void run() {

                            int statusBarHeight = (int) Math.ceil(25 * vg.getContext().getResources().getDisplayMetrics().density);
                            statusBar.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, statusBarHeight));
                            statusBar.setBackgroundColor(act.getResources().getColor(colorResID));
                            statusBar.setId(13371337);
                            vg.addView(statusBar, 0);
                        }
                    });
                    return statusBar;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    else if (act.getWindow() != null) {
        act.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        act.getWindow().setStatusBarColor(act.getResources().getColor(colorResID));
    }
    return null;
}

private static boolean applyColoredStatusBar( Activity act, int colorResID ) {
    final Window window = act.getWindow();
    final int flag;
    if (window != null) {
        View decor = window.getDecorView();
        if (decor != null) {
            flag = resolveTransparentStatusBarFlag(act);

            if (flag != 0) {
                decor.setSystemUiVisibility(flag);
                return true;
            }
            else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
                act.findViewById(android.R.id.content).setFitsSystemWindows(false);
                setTranslucentStatus(window, true);
                final SystemBarTintManager tintManager = new SystemBarTintManager(act);
                tintManager.setStatusBarTintEnabled(true);
                tintManager.setStatusBarTintColor(colorResID);
            }
        }
    }
    return false;
}

public static int resolveTransparentStatusBarFlag( Context ctx ) {
    String[] libs = ctx.getPackageManager().getSystemSharedLibraryNames();
    String reflect = null;

    if (libs == null)
        return 0;

    final String SAMSUNG = "touchwiz";
    final String SONY = "com.sonyericsson.navigationbar";

    for (String lib : libs) {

        if (lib.equals(SAMSUNG)) {
            reflect = "SYSTEM_UI_FLAG_TRANSPARENT_BACKGROUND";
        }
        else if (lib.startsWith(SONY)) {
            reflect = "SYSTEM_UI_FLAG_TRANSPARENT";
        }
    }

    if (reflect == null)
        return 0;

    try {
        Field field = View.class.getField(reflect);
        if (field.getType() == Integer.TYPE) {
            return field.getInt(null);
        }
    } catch (Exception e) {
    }

    return 0;
}

@TargetApi(Build.VERSION_CODES.KITKAT)
public static void setTranslucentStatus( Window win, boolean on ) {
    WindowManager.LayoutParams winParams = win.getAttributes();
    final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
    if (on) {
        winParams.flags |= bits;
    }
    else {
        winParams.flags &= ~bits;
    }
    win.setAttributes(winParams);
}

Ответ 8

Создайте родительский стиль Theme.AppCompat

<style name="AppTheme" parent="Theme.AppCompat">
     <item name="android:colorPrimary">#005555</item>
     <item name="android:colorPrimaryDark">#003333</item>
</style>

И поместите getSupportActionBar().getThemedContext() в onCreate().

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);
        getSupportActionBar().getThemedContext();
}

Ответ 9

Я знаю, что это не отвечает на вопрос, но с Material Design (API 21+) мы можем изменить цвет строки состояния, добавив эту строку в объявление темы в styles.xml:

<!-- MAIN THEME -->
<style name="AppTheme" parent="@android:style/Theme.Material.Light">
    <item name="android:actionBarStyle">@style/actionBarCustomization</item>
    <item name="android:spinnerDropDownItemStyle">@style/mySpinnerDropDownItemStyle</item>
    <item name="android:spinnerItemStyle">@style/mySpinnerItemStyle</item>
    <item name="android:colorButtonNormal">@color/myDarkBlue</item>
    <item name="android:statusBarColor">@color/black</item>
</style>

Обратите внимание на android:statusBarColor, где мы можем определить цвет, в противном случае используется значение по умолчанию.