Android:具有动态 actionBar 颜色和 DrawerLayout 的透明状态栏

Posted

技术标签:

【中文标题】Android:具有动态 actionBar 颜色和 DrawerLayout 的透明状态栏【英文标题】:Android: Transparent status bar with dynamic actionBar colors and DrawerLayout 【发布时间】:2016-11-07 02:01:47 【问题描述】:

我有一个DrawerLayout 的活动。我们的客户要求我们根据从DrawerLayout 中选择的项目来动态更改此活动的操作栏颜色和相应的状态栏颜色。这很容易做到。但是,我的问题是当我动态更改状态栏颜色时,我无法保持状态栏透明。当我打开抽屉时,彩色状态栏覆盖了DrawerLayout 的顶部,如下所示:

但是,我希望我的 DrawerLayout 看起来像这样:

我可以通过以下行来做到这一点:

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

不过,我的问题不是我不能设置状态栏的透明度。我的问题是状态栏和操作栏颜色的动态变化不适用于windowTranslucentStatus。即使在我调用getWindow().setStatusBarColor() 之后,我的状态栏颜色仍然是colorPrimaryDark(上图中状态栏上可见的芥末黄色)。

现在,我关注了 this 教程和 this 和 this *** 问题以及许多其他问题,但无法解决问题。所有这些文章都说,一旦我将windowTranslucentStatus 设置为trueActionBar 将移动到状态栏下方的顶部(以便状态栏与操作栏重叠)。之后,我应该能够为操作栏添加一些填充,并且简单地更改操作栏颜色也会导致相同颜色的更暗状态栏,因为状态栏实际上是半透明的并且与我的操作栏重叠。但是,由于某种原因,这在我的情况下不会发生。无论我将fitsSystemWindows 设置为true 还是false,或者完全删除该属性,操作栏都会保持原样。操作栏总是低于状态栏,当然,如果我设置透明度,它总是黄色的。

在以编程方式更改状态栏颜色时,我还尝试将 alpha 设置为状态栏颜色。这确实使状态栏有点透明,但它看起来很奇怪,因为它不再是真正的 dark 了。删除CoordinatorLayout 也无济于事。我花了几个小时试图解决这个问题,现在很沮丧。任何帮助是极大的赞赏。

我的activity_main

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/drawer_layout"
android:layout_
android:layout_
android:fitsSystemWindows="true"
tools:openDrawer="start">

<include
    layout="@layout/app_bar_main"
    android:layout_
    android:layout_ />

<android.support.design.widget.NavigationView
    android:id="@+id/nav_view"
    android:layout_
    android:layout_
    android:layout_gravity="start"
    android:fitsSystemWindows="true">

    <include layout="@layout/nav_header_main" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/nav_menu_recyclerview"
        android:layout_
        android:layout_
        android:layout_marginTop="@dimen/nav_header_height"
        android:clipToPadding="false"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/size_14dp"
        app:layoutManager="LinearLayoutManager" />
</android.support.design.widget.NavigationView>

</android.support.v4.widget.DrawerLayout>

这是我的app_bar_main 的 XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_
android:layout_
android:fitsSystemWindows="true">

<android.support.design.widget.AppBarLayout
    android:layout_
    android:layout_
    android:theme="@style/AppTheme.AppBarOverlay"
    app:elevation="0dp">


    <FrameLayout
        android:id="@+id/toolbar_container"
        android:layout_
        android:layout_
        app:popupTheme="@style/AppTheme.PopupOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_
            android:layout_
            android:background="?attr/colorPrimary" />

        <com.quintype.sakshipost.Widgets.CustomMaterialSearchView
            android:id="@+id/search_view"
            android:layout_
            android:layout_ />
    </FrameLayout>

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_main" />

</android.support.design.widget.CoordinatorLayout>

【问题讨论】:

【参考方案1】:

您的问题是因为getWindow().setStatusBarColor() 不能很好地与DrawerLayout 一起使用。为了使您的状态栏保持半透明以及能够更改其颜色,您必须遵循以下过程:

在您的 v21/styles.xml 文件中添加/修改以下主题,如下所示:

<style name="AppTheme.NoActionBar" parent="AppTheme">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="android:windowTranslucentStatus">true</item>
</style>

这是标准DrawerLayout 使用的主题(当然,假设您在具有DrawerLayout 的活动中使用此主题)。如您所知,这将使您的状态栏变为半透明。

接下来,从您的app_bar_main 中的CoordinatorLayout 中删除android:fitsSystemWindows="true"

接下来,无论您要更改工具栏/状态栏的颜色,请使用与工具栏相同的颜色使用drawerLayout.setStatusBarBackground(colorDrawable)(当然,假设对您的DrawerLayout 的引用称为drawerLayout )。请注意,drawerLayout.setStatusBarBackground() 方法采用 Drawable 对象,与 window.setStatusBarColor() 方法采用 int 颜色不同,因此您可能必须使用以下方式将颜色转换为可绘制对象:

new ColorDrawable(ContextCompat.getColor(getApplicationContext(), R.color.colorPrimary))

这将确保您的状态栏是半透明的,并使其能够更改颜色。希望你能够让它发挥作用。

【讨论】:

【参考方案2】:

正如文档所说here,不得设置 FLAG_TRANSLUCENT_STATUS。

要使此功能生效,窗口必须绘制系统栏背景,并且不能设置 FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 和 FLAG_TRANSLUCENT_STATUS。

【讨论】:

我也试过这个,但这会导致与第一个屏幕截图相同的行为。我希望它看起来像第二个,但仍然能够更改状态栏颜色。我还可以简单地使状态栏透明并在其下方扩展操作栏。但我也做不到。 :(【参考方案3】:

我在我的应用程序中这样做。

<style name="AppTheme" parent="Theme.AppCompat.Dark">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>

colorPrimary 将设置状态栏颜色,但前提是您重新启动活动。

因此将其设置为透明的黑色,然后在您的代码中重新启动活动。您可以在样式中创建多个样式,使用不同的 colorPrimary 值,然后在您的活动中执行此操作。

//onClick or condition statement here
setTheme(R.style.AppThemeLight);
setContentView(R.layout.activity_link_manager_light);
restart();


public void restart()
Intent i = getBaseContext().getPackageManager()
            .getLaunchIntentForPackage( getBaseContext().getPackageName() );
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(i);

我认为您不需要重置 contentview,除非您也切换布局,如果没有它就无法工作,不确定是否可以尝试将其重置为相同的布局。

这绝对适合我,但我从未尝试使用透明值。

您可以使用此方法重置整个应用程序主题并切换到硬编码不同颜色的新布局,只需在布局中保留所有 id 相同,在代码中您将获得正确的 id在您将 setContentView 设置为具有您在某处调用的 ID 的正确布局之后,您引用 findViewByID 。每个布局的 ID 都不同,但您始终会在调用 findViewByID 时获得当前使用 setContentView 设置的布局 ID。

您还可以将当前主题保存到 sharedpref 文件中,并在调用 setContentView 之前在 applaunch 时使用开关设置主题(否则状态栏颜色不会改变)

考虑一下这段代码。顺便说一下,这接近 onCreate 的开始

String Theme;
    SaveData = getSharedPreferences(SaveFileName,0);
    Theme = SaveData.getString("Theme","Default Theme");
switch(Theme)
        case "Light Theme":
            setTheme(R.style.AppThemeLight);
            setContentView(R.layout.activity_link_manager_light);
            ListTextViewID = R.id.AppListTextViewLight;
            ListRowID = R.layout.app_list_item_light;
            break;

我在设置 contentview 之前设置 apptheme 的方式是状态栏颜色更改起作用的原因。

【讨论】:

你可能没有完全理解我的问题。我可以使用getWindow().setStatusBarColor(int color); 轻松设置状态栏的颜色,您无需为此重新启动活动,也无需多次调用setContentView()。但是,我的目标是将状态栏设置为 透明 并在 下方 绘制操作栏。 (此外,为这样一件小事多次重启活动是一种非常不雅的技巧。) 哦,是的,我错过了,您也可以通过将主题父级从“.NoActionBar”切换到“.Light”来添加操作栏,您可以使用主题设置颜色也是。这将做你想做的一切,但我不知道如何在不重新启动应用程序的情况下做到这一点。 您还可以通过线性布局或查看操作栏所在的位置以编程方式添加自定义操作栏,并以编程方式隐藏和显示它:“View.setVisibility(View.GONE);” "View.setVisibility(View.VISIBLE);" 实际上纠正自己我不认为它会重新启动应用程序,只是活动,它有一个无痛的动画而且它很快(至少在 MM 上是这样) 相信我。多次重新启动活动不是您应该做的事情。您也不需要更改主题。您似乎对 Android 很陌生。你曾经和DrawerLayout一起工作过吗?

以上是关于Android:具有动态 actionBar 颜色和 DrawerLayout 的透明状态栏的主要内容,如果未能解决你的问题,请参考以下文章

如何更改 Android 中各个片段的 ActionBar 颜色?

如何在 Android 3.0 及更高版本中更改 ActionBar 的触摸效果颜色

如何在 Android 3.0 及更高版本中更改 ActionBar 的触摸效果颜色

Android 5.0 ActionBar的Title颜色怎么修改

ActionBar 自定义标题颜色

如何使用滑动抽屉更改ActionBar的颜色?