棒棒糖:在statusBar后面绘制,其颜色设置为透明


142

我仅将主题中的以下行设置为Lollipop的statusBar颜色设置为透明:

<item name="android:statusBarColor">@android:color/transparent</item>

现在我需要在它后面绘制,但是我无法在它后面绘制任何视图。我知道如何使用该windowTranslucentStatus属性,但是不想使用此属性,因为它会忽略statusBar设置为透明的颜色。


2
您还可以使用android:fitsSystemWindows="true"
Aznix

Answers:


385

方法1:

要获得完全透明的状态栏,您必须使用statusBarColor,该功能仅在API 21及更高版本上可用。windowTranslucentStatus可在API 19及更高版本上使用,但会为状态栏添加有色背景。但是,设置windowTranslucentStatus确实实现了更改statusBarColor为透明无法实现的一件事:它设置了SYSTEM_UI_FLAG_LAYOUT_STABLESYSTEM_UI_FLAG_LAYOUT_FULLSCREEN标志。获得相同效果的最简单方法是手动设置这些标志,从而有效地禁用由Android布局系统施加的插入效果,并让您自己养护自己。

您可以在onCreate方法中调用以下行:

getWindow().getDecorView().setSystemUiVisibility(
    View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);

还要确保在/res/values-v21/styles.xml中设置透明度:

<item name="android:statusBarColor">@android:color/transparent</item>

或以编程方式设置透明度:

getWindow().setStatusBarColor(Color.TRANSPARENT);

这种方法的好处是,通过用透明状态栏替换有色半透明状态栏,也可以在API 19上使用相同的布局和设计。

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

方法2:

如果您只需要在状态栏下绘制背景图像,而不是在其后放置视图,则可以通过将活动主题的背景设置为所需图像并设置状态栏的透明度来实现,如方法#所示。 1。这是我几个月前用来为Android Police文章创建屏幕截图的方法。

方法3:

如果您必须忽略某些布局的标准系统插图,而又要使其在其他布局中工作,那么唯一可行的方法是使用经常链接的ScrimInsetsFrameLayout类。当然,并非在所有情况下都需要该类中完成的某些事情。例如,如果您不打算使用合成状态栏叠加层,则只需注释掉init()方法中的所有内容,而不必费心向attrs.xml文件添加任何内容。我已经看到了这种方法的工作原理,但是我想您会发现它带来了其他一些含义,这可能需要很多工作才能解决。

我还看到您反对包装多个布局。如果将一种布局包装在另一种布局中match_parent(高度和宽度都相同),则对性能的影响微不足道,无需担心。无论如何,您可以通过将其扩展的类更改为FrameLayout您喜欢的任何其他类型的Layout类来完全避免这种情况。它将正常工作。


9
非常感谢,设置SYSTEM_UI_FLAG_LAYOUT_STABLESYSTEM_UI_FLAG_LAYOUT_FULLSCREEN标志是我一直在寻找的解决方案。
alxscms 2015年

3
我搜索了您一个月的第一个解决方案。谢谢!
NeoKree

1
你好 您的代码运行正常。但是,当我退出该片段时,应如何回滚更改?
TheOnlyAnil 2015年

3
这不适用于CollapsingToolbarLayoutToolbar:状态栏保持不完全透明,并且android:statusBarColor不起作用
Konstantin Konopko

谢谢。如果您随后想要恢复为非全屏活动,请阅读developer.sonymobile.com/knowledge-base/tutorials/…
CoolMind

43

这适用于我的情况


// Create/Set toolbar as actionbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

// Check if the version of Android is Lollipop or higher
if (Build.VERSION.SDK_INT >= 21) {

    // Set the status bar to dark-semi-transparentish
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
            WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

    // Set paddingTop of toolbar to height of status bar.
    // Fixes statusbar covers toolbar issue
    toolbar.setPadding(0, getStatusBarHeight(), 0, 0);
}

// A method to find height of the status bar
public int getStatusBarHeight() {
    int result = 0;
    int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
    if (resourceId > 0) {
        result = getResources().getDimensionPixelSize(resourceId);
    }
    return result;
}

有关使用statusBar的更多信息:youtube.com/watch? v= _mGDMVRO3iE



@TheOnlyAnil定义一个固定的工具栏高度:)“ 56dp”左右应该看起来不错
Michael Michael

4
完全不支持,没有文档记录这样的状态栏高度,并且肯定会在将来的版本中中断。请改用fitsSystemWindows =“ true”。
格雷格·恩尼斯

1
好吧,我这样做也是因为有时候你不得不这么做。
格雷格·恩尼斯

2
根据Chris Banes(Google工程师)的演讲,这是一个非常糟糕的主意:youtube.com/watch?
v=_mGDMVRO3iE

1
@Michael FWIW,我过去已经这样做过,而WindowInsets api是一种(方法)做到这一点“应该很简单,无需我们思考就可以完成”,但事实并非如此,这是一个la脚的无用的API,添加了一个很多不必要的开销。Google始终会完成80%的工作,将最后20%的工作留给开发人员……他们一路破解直到实现。_(ツ)_ /¯
马丁Marconcini

21

试试这个主题

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <!-- Customize your theme here. -->
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
    <item name="colorPrimaryDark">@android:color/transparent</item>
    <item name="colorPrimary">@color/md_blue_200</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:windowTranslucentStatus">true</item>
</style>

请确保您的布局设置

android:fitsSystemWindows="false"

4
设置android:fitsSystemWindows="false"将工具栏切成两半。
哈马德·纳西尔

16

代替

<item name="android:statusBarColor">@android:color/transparent</item>

使用以下内容:

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

并确保删除“ MainActivity”布局上的顶部填充(默认情况下已添加)。

请注意,这不会使状态栏完全透明,并且状态栏上仍会出现“褪色的黑色”覆盖。


2
使用时<item name="android:windowTranslucentStatus">true</item>,它会使android在状态栏下放置一个褪色的黑色背景,这不是我想要的。尽管没有这种黑色褪色的背景吗?
alxscms 2015年

1
我已经尝试了很多方法,但是找不到消除褪色的黑色背景的方法。因此,在结束研究时,我说这在Android上是不可能的(即使使用ScrimLayout也无法做到)。这种方式很有意义,因为它可以确保始终保持状态栏的正确可读性。我将在上面更新我的答案。
Jeroen Mols 2015年

我认为能够在状态栏上放置透明颜色而又不能在其后面绘制将是非常奇怪的。我理解您为什么说不能删除此黑色褪色的背景是有道理的,但是绝对不需格外小心以使状态栏图标保持可见。这是一篇有关android Police的文章,显示了使用透明状态栏androidpolice.com/2014/07/04/…。我将尝试与作者联系。
alxscms 2015年

1
希望你能和他取得联系。我也对这样做很感兴趣:)
Jeroen Mols 2015年

大!也更新了我的答案。
Jeroen Mols,2015年

9

Cody Toombs的解决方案几乎帮了我大忙。我不确定这是否与Xamarin有关,但是我现在有一个可以接受的解决方案:

例

这是我的设置:

我有一个Android项目,其中引用了Android.Support v4和v7软件包。我定义了两种样式:

values / styles.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <style name="MyStyle" parent="@style/Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowTranslucentStatus">true</item>
    </style>
</resources>

values-v21 / styles.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
    <style name="MyStyle" parent="@style/Theme.AppCompat.Light.NoActionBar">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

AndroidManifest定位到“ MyStyle”:

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.agn.test.test">
    <uses-sdk android:minSdkVersion="10" />
    <application android:allowBackup="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:theme="@style/MyStyle">
    </application>
</manifest>

最后是Main Activity中的代码:

[Activity (Label = "Test", MainLauncher = true, Icon = "@mipmap/icon")]
public class MainActivity : Activity
{
    protected override void OnCreate (Bundle savedInstanceState)
    {
        base.OnCreate (savedInstanceState);

        SetContentView (Resource.Layout.Main);
        //Resource.Layout.Main is just a regular layout, no additional flags. Make sure there is something in there like an imageView, so that you can see the overlay.

        var uiOptions = (int)Window.DecorView.SystemUiVisibility;
        uiOptions ^= (int)SystemUiFlags.LayoutStable;
        uiOptions ^= (int)SystemUiFlags.LayoutFullscreen;
        Window.DecorView.SystemUiVisibility = (StatusBarVisibility)uiOptions;

        Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds);
    }
}

注意,我设置了DrawsSystemBarBackgrounds标志,这使所有区别

Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds); 

我花了很多时间去做正确的事,实际上花了太多时间。希望这个答案可以帮助任何尝试实现同一目标的人。


1
android:windowTranslucentStatus需要API等级19以上,怎么可能是你正在使用它在你的价值观/ styles.xml同时具有一个android:minSdkVersion10?
mradzinski

7

@Cody Toombs的答案导致了一个问题,该问题将布局置于导航栏的后面。因此,我发现使用解决方案由@Kriti给出

这是相同的Kotlin代码段:

if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
    setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, true)
}

if (Build.VERSION.SDK_INT >= 19) {
    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
}

if (Build.VERSION.SDK_INT >= 21) {
    setWindowFlag(this, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, false)
    getWindow().setStatusBarColor(Color.TRANSPARENT)
}

private fun setWindowFlag(activity: Activity, bits: Int, on: Boolean) {

    val win: Window = activity.getWindow()

    val winParams: WindowManager.LayoutParams = win.getAttributes()
    if (on) {
        winParams.flags = winParams.flags or bits
    } else {
        winParams.flags = winParams.flags and bits.inv()
    }
    win.setAttributes(winParams)
}

您还需要添加

android:fitsSystemWindows="false"

布局的根视图。


3

我遇到了同样的问题,所以我创建了在状态栏API后面绘制的ImageView 19+

在状态栏gist.github.com后面设置自定义图像

public static void setTransparent(Activity activity, int imageRes) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
        return;
    }
    // set flags
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
    } else {
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
    }

    // get root content of system window
    //ViewGroup rootView = (ViewGroup) ((ViewGroup) activity.findViewById(android.R.id.content)).getChildAt(0);
    // rootView.setFitsSystemWindows(true);
    // rootView.setClipToPadding(true);

    ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
    if (contentView.getChildCount() > 1) {
        contentView.removeViewAt(1);
    }

    // get status bar height
    int res = activity.getResources().getIdentifier("status_bar_height", "dimen", "android");
    int height = 0;
    if (res != 0)
        height = activity.getResources().getDimensionPixelSize(res);

    // create new imageview and set resource id
    ImageView image = new ImageView(activity);
    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, height);
    image.setLayoutParams(params);
    image.setImageResource(imageRes);
    image.setScaleType(ScaleType.MATRIX);

    // add image view to content view
    contentView.addView(image);
    // rootView.setFitsSystemWindows(true);

}

2

您可以使用ScrimInsetFrameLayout

https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java

android:fitsSystemWindows =“ true”应该在稀松布艺布局上设置!


我看到了该类,但是如果我想使用a RelativeLayout而不是a FrameLayout怎么办?
alxscms 2015年

3
在框架布局内使用相对布局。
Murtaza Khursheed Hussain,2015年

2
在布局中嵌套布局绝对不是我对性能的解决方案
alxscms 2015年

1
应用程序的性能取决于很多因素,这些因素可能会有所不同。如果您没有出路,请尝试一下。最好的运气
Murtaza Khursheed Hussain 2015年

我明白您的意思,但是必须有另一种解决方案,如果没有,可能有一种方法可以在任何布局上实现在此自定义框架布局中实现的功能。但是,无论如何
都要

1

与发布的某些解决方案类似,但在我的情况下,我将状态栏透明化,并以一些负的边距来固定操作栏的位置

if (Build.VERSION.SDK_INT >= 21) {
    getWindow().setStatusBarColor(Color.TRANSPARENT);
    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) toolbar.getLayoutParams();
    lp.setMargins(0, -getStatusBarHeight(), 0, 0);
}

我在工具栏和根视图中使用了

android:fitsSystemWindows="true"

1
getStatusBarHeight()不是标准的
Roel

此方法是在@ mike-milla的解决方案上实现的。public int getStatusBarHeight(){int result = 0; int resourceId = getResources()。getIdentifier(“ status_bar_height”,“ dimen”,“ android”); 如果(resourceId> 0){结果= getResources()。getDimensionPixelSize(resourceId); 返回结果;}
jegumi

谢谢。我这样做是:AppBarLayout.LayoutParams lp =(AppBarLayout.LayoutParams)toolbar.getLayoutParams(); lp.topMargin + = getStatusBarHeight();
CoolMind

1

有很好的图书馆StatusBarUtil@laobie这有助于轻松地绘制图像中的状态栏。

只需添加您的build.gradle

compile 'com.jaeger.statusbarutil:library:1.4.0'

然后在活动集中

StatusBarUtil.setTranslucentForImageView(Activity activity, int statusBarAlpha, View viewNeedOffset)

在布局中

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:orientation="vertical">

    <ImageView
        android:layout_alignParentTop="true"
        android:layout_width="match_parent"
        android:adjustViewBounds="true"
        android:layout_height="wrap_content"
        android:src="@drawable/toolbar_bg"/>

    <android.support.design.widget.CoordinatorLayout
        android:id="@+id/view_need_offset"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@android:color/transparent"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>

        <!-- Your layout code -->
    </android.support.design.widget.CoordinatorLayout>
</RelativeLayout>

有关更多信息,请从github页面下载演示或克隆并使用所有功能。

注意:支持KitKat及更高版本。

希望对别人有帮助!


0

在Android Studio 1.4中,带有样板代码的模板项目Overlay在AppbarLayout和/或工具栏上设置了主题。还可以通过fitSystemWindowattribute = true 将它们设置为在状态栏后面呈现。这将导致仅将工具栏显示在状态栏的正下方,而其他所有内容将显示在工具栏的正下方。因此,上面提供的解决方案不能单独使用。您将必须进行以下更改。

  • 删除覆盖主题或将其更改为工具栏的非覆盖主题。
  • 将以下代码放入您的styles-21.xml文件中。

    @android:颜色/透明

  • 将此主题分配给包含AndroidManifest.xml文件中导航抽屉的活动。

这将使导航抽屉在透明状态栏后面呈现。


0

您需要做的就是在主题中设置这些属性

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

1
我很确定,这会使您的布局落在UI导航按钮(带有屏幕导航的设备)的下面。这使得底部导航视图无法在我们的应用程序中访问,因此我们在Nexus上进行测试后放弃了这些标志
EpicPandaForce

0

接受的答案使用CollapsingToolbarLayout为我工作。不过,请务必注意,它setSytstemUiVisibility()会覆盖以前对该函数的所有调用。因此,如果在同一视图的其他位置使用该功能,则需要包含View.SYSTEM_UI_FLAG_LAYOUT_STABLEView.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN标志,否则它们将被新调用覆盖。

对我来说就是这种情况,一旦我将两个标志添加到另一个我要打电话的位置setSystemUiVisibility(),接受的答案就可以正常工作。


0

我将在此处添加更多信息。最新的Android开发使在状态栏中处理许多案件变得非常容易。以下是我对styles.xml

  1. 背景颜色:对于SDK 21+,如提及的许多答案所述,它<item name="android:windowTranslucentStatus">true</item> 将使状态栏透明并显示在UI的前面。您的活动将占据顶部的整个空间。
  2. 背景色:对于SDK 21+,同样,它<item name="android:statusBarColor">@color/your_color</item>只会为状态栏提供一种颜色,而不会影响其他任何颜色。

  3. 但是,在更高版本的设备(Android M / +)中,图标开始以不同的阴影显示。如果您覆盖styles.xml文件values-23夹中的文件并添加,则操作系统可以为SDK 23 / +的图标提供深灰色阴影<item name="android:windowLightStatusBar">true</item>
    这样,如果状态栏为浅色,您将为用户提供一个更可见的状态栏(考虑一下许多google应用的背景为浅色,但图标在那里显示为灰色)。
    如果您通过第2点为状态栏添加颜色,我建议您使用此功能

  4. 在最新的设备中,SDK 29 / +具有系统范围的明暗主题,可由用户控制。作为开发人员,我们还应该在新values-night文件夹中覆盖样式文件,以为用户提供2种不同的体验。
    在这里,我再次发现要点2对于提供“状态栏的背景色”有效。但是系统没有更改我的应用程序状态栏图标的颜色。由于我的日常版本的样式由较浅的主题组成,因此这意味着用户的可见性较低(较浅背景上的白色图标),
    可以使用第3点方法或覆盖文件values-29夹中的样式文件并使用较新的样式来解决此问题。api <item name="android:enforceStatusBarContrast">true</item>。如果您的背景颜色太浅,则会自动将灰色调强制给图标。


-1

这是我用来完成此任务的主题:

<style name="AppTheme" parent="@android:style/Theme.NoTitleBar">

    <!-- Default Background Screen -->
    <item name="android:background">@color/default_blue</item>
    <item name="android:windowTranslucentStatus">true</item>

</style>

1
有一些奇怪的拒绝者。即使某个解决方案适合您和其他人,他们也会投票反对,而不是传递另一个答案。
CoolMind

我要的只是一个解释。我认为人们应该不加解释就可以拒绝投票。
Droid Chris

我也是这么认为。
CoolMind

我将说明背景选项在此捆绑包中无法正常工作。请更正您的答案。
莫罗佐夫

嗯...您正在使用哪个版本的Android?我使用Android中M.这种配置
Droid的克里斯-

-3

正确的解决方案是将“活动”标签下的XML属性更改为以下样式。才行

  android:theme="@style/Theme.AppCompat.Light.NoActionBar"
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.