Android Material:状态栏颜色无法更改

58

我正在开发一个简单的应用程序来测试 Material Design。我正在使用 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>

现在我按照Material设计准则定义了我的主题:

<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(..)

但是在 API 级别 21 及以上,可以使用 setStatusBar 颜色。为什么如果我在主题中定义了 colorPrimaryDark 并使用 appcompact,则状态栏不会更改颜色?有人能帮忙吗?


1
似乎是appcompat-v7中的一个bug。你介意在https://code.google.com/p/android/issues/list/上提交一个问题吗?这样我们就可以跟踪它了。请在问题中包含你的布局和样式XML。谢谢! - alanv
应该也有WindowCompat方法来设置状态栏颜色。可以在问题中提到或者提交一个单独的问题。 - alanv
谢谢alanv的回答。我会进一步调查这个问题,检查是否有做错的地方,如果找不到解决方法,我会提交问题。 - FrancescoAzzola
1
可能是[状态栏颜色未显示-5.0棒棒糖Android Studio:(AppCompat-v7:r21)]的重复问题。(https://dev59.com/_l8d5IYBdhLWcg3wt0AQ) - Jared Burrows
请参考:https://dev59.com/x2Eh5IYBdhLWcg3wpEtF#36753271 - Harpreet
10个回答

64

虽然在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版本,因此这是一种边缘情况的解决方法。


63

状态栏是操作系统拥有的系统窗口。在 Android 5.0 之前的设备上,应用程序没有权限修改其颜色,因此 AppCompat 库无法支持旧版本平台的此功能。最好的解决方案是使用 AppCompat 支持为应用程序中的 ActionBar 和其他常见 UI 部件提供颜色。


44
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方法中。这对我很有帮助。


13

正如其他人所提到的那样,这可以通过在 Activity 的 onCreate() 方法中添加以下内容来轻松解决:

    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)


10

AppCompat v7:21.0.0不支持状态栏着色。

来自Android开发者博客文章

在旧平台上,AppCompat尽可能地模拟颜色主题。目前仅限于对操作栏和一些小部件进行着色。

这意味着AppCompat库只会在Lollipop及以上版本中着色状态栏。


因此,这是义务性的(并且在其他答案中也出现): 如果(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){... - Carlos Gómez

9

切换到AppCompatActivity并在工具栏上添加25dp的paddingTop,然后打开

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

然后,工具栏会移到顶部。

2
这将仅适用于API 19及以上版本,对于以下版本不起作用。 - Stoycho Andreev

2

这个解决方案可以设置Lollipop、Kitkat和一些早期的设备(三星和索尼)的状态栏颜色。 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);
}

0

我知道这并不是回答问题的方法,但使用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,我们可以在其中定义颜色,否则将使用默认值。

1
我想这是因为“我知道这个并不能回答问题,但是...”,而问题明确说明了“我想要在Android 5之前更改状态栏颜色...”。你将这个作为答案提交给了问题,但很明显这不是正确的答案。我并不是在批评你,因为我理解你试图提供帮助,但希望这能让你明白问题所在,以便以后避免类似情况。 - themightyjon

0

将父级样式设置为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();
}

3
在使用AppCompat时,不要在颜色值前面加上android:前缀。 - Michiel
这段代码与问题无关。前缀是针对API 21+的,而且代码并没有做任何事情。 - Jared Burrows
3
一个 getter 被调用,它会怎样改变任何东西? - Ostkontentitan

0

**

淘气的LOLLIPOP的解决方案

**

你好,我在编程中遇到了一个很大的问题,我的颜色比预期的要暗...这是解决方案,可以避免使用TranslucentStatus时状态栏后面的阴影...

所以在你的Java活动中,你需要这样做:

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

在styles.xml文件中,您需要设置背景颜色(此颜色将成为状态栏的颜色):

<style name="AppCompat" parent="Theme.AppCompat">
    <item name="android:colorBackground">@color/YOUR_STATUS_BAR_COLOR</item>
</style>

在所有的布局中,您需要添加一个布局作为您的背景:

<LinearLayout
    android:background="@color/YOUR_BACKGROUND_COLOR"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="bottom"
    />

当然,如果你想使用@color/或者只是名称... 你需要在colors.xml中设置:

<color name="YOUR_STATUS_BAR_COLOR">#cf031c</color>
<color name="YOUR_BACKGROUND_COLOR">#383838</color>

这是我们完成此操作的整个过程:创建或更改状态栏颜色的正确方法是什么?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接