Lollipop: dibuja detrás de statusBar con su color configurado en transparente

142

He configurado el color de mi barra de estado en transparente para Lollipop solo con la siguiente línea en mi tema:

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

Ahora necesito dibujar detrás de él, pero no puedo ver ningún dibujo detrás. Sé cómo hacerlo con la windowTranslucentStatuspropiedad, pero no quiero usar esta propiedad, ya que ignorará el color del statusBar establecido en transparente.

alxscms
fuente
2
También puedes usarandroid:fitsSystemWindows="true"
Aznix

Respuestas:

385

Método 1:

Para lograr una barra de estado completamente transparente, debe usar statusBarColor, que solo está disponible en API 21 y superior. windowTranslucentStatusestá disponible en API 19 y superior, pero agrega un fondo teñido para la barra de estado. Sin embargo, la configuración windowTranslucentStatuslogra una cosa que no es el cambio statusBarColora transparente: establece las banderas SYSTEM_UI_FLAG_LAYOUT_STABLE y SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN. La forma más fácil de obtener el mismo efecto es establecer manualmente estos indicadores, lo que desactiva de manera efectiva las inserciones impuestas por el sistema de diseño de Android y te deja valerte por ti mismo.

Llama a esta línea en su onCreatemétodo:

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

Asegúrese de establecer también la transparencia en /res/values-v21/styles.xml:

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

O establezca la transparencia mediante programación:

getWindow().setStatusBarColor(Color.TRANSPARENT);

El lado bueno de este enfoque es que los mismos diseños y diseños también se pueden usar en API 19 al cambiar la barra de estado transparente por la barra de estado translúcida teñida.

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

Método 2:

Si solo necesita pintar una imagen de fondo debajo de su barra de estado, en lugar de colocar una vista detrás de ella, esto puede hacerse simplemente configurando el fondo del tema de su actividad a la imagen deseada y configurando la transparencia de la barra de estado como se muestra en el método # 1) Este fue el método que usé para crear las capturas de pantalla para el artículo de Android Police de hace unos meses.

Método 3:

Si tiene que ignorar las inserciones del sistema estándar para algunos diseños mientras los mantiene trabajando en otros, la única forma viable de hacerlo es trabajar con la ScrimInsetsFrameLayoutclase a menudo vinculada . Por supuesto, algunas de las cosas que se hacen en esa clase no son necesarias para todos los escenarios. Por ejemplo, si no planea usar la superposición de la barra de estado sintética, simplemente comente todo en el init()método y no se moleste en agregar nada al archivo attrs.xml. He visto que este enfoque funciona, pero creo que encontrará que trae algunas otras implicaciones que pueden ser mucho trabajo para sortear.

También vi que te opones a envolver múltiples diseños. En el caso de envolver un diseño dentro de otro, donde ambos tienen match_parentaltura y ancho, las implicaciones de rendimiento son demasiado triviales para preocuparse. En cualquier caso, puede evitar esa situación por completo cambiando la clase que se extiende FrameLayouta cualquier otro tipo de clase de diseño que desee. Funcionará bien.

Cody Toombs
fuente
9
Muchas gracias, configurar las banderas SYSTEM_UI_FLAG_LAYOUT_STABLEy SYSTEM_UI_FLAG_LAYOUT_FULLSCREENfue la solución que estaba buscando.
alxscms
3
Busqué tu primera solución durante un mes. ¡Gracias!
NeoKree
1
Hola. Tu código funciona perfectamente bien. Pero cuando salgo del fragmento, ¿cómo debo revertir los cambios?
TheOnlyAnil
3
Esto no funciona con CollapsingToolbarLayouty Toolbar: la barra de estado no es completamente translúcida y android:statusBarColorno tiene efecto
Konstantin Konopko
Gracias. Si luego desea volver a una actividad que no sea de pantalla completa, lea developer.sonymobile.com/knowledge-base/tutorials/… .
CoolMind
43

Esto funcionó para mi caso


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

Para obtener más información sobre cómo trabajar con statusBars: youtube.com/watch?v=_mGDMVRO3iE


Miguel
fuente
@TheOnlyAnil define una altura de barra de herramientas fija :) "56dp" o algo así debería verse bien
Michael
44
Obtener la altura de la barra de estado como esta es totalmente incompatible, indocumentado y seguramente se romperá en futuras versiones. Utilice fitSystemWindows = "true" en su lugar.
Greg Ennis
1
Bueno, lo estoy haciendo también porque a veces solo tienes que hacerlo.
Greg Ennis
2
Esta es una muy mala idea, según Chris Banes (ingeniero de Google) en esta charla: youtube.com/watch?v=_mGDMVRO3iE
Martin Marconcini
1
@Michael FWIW, he hecho esto en el pasado y la API de WindowInsets (método) para hacer esto "debería ser simple y hacerlo sin que tengamos que pensar en ello", pero no lo es, es una API inútil cojo que agrega un gran cantidad de gastos generales innecesarios. Google siempre está completo al 80% y deja el último 20% a los desarrolladores ... que piratean todo el camino hasta que lo hacen posible. ¯_ (ツ) _ / ¯
Martin Marconcini
21

Prueba este tema

<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>

Asegúrese de que su conjunto de diseño

android:fitsSystemWindows="false"
Son Nguyen Thanh
fuente
44
la configuración android:fitsSystemWindows="false"es cortar la barra de herramientas por la mitad.
Hammad Nasir
16

En vez de

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

Use lo siguiente:

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

Y asegúrese de eliminar el relleno superior (que se agrega de forma predeterminada) en su diseño 'MainActivity'.

Tenga en cuenta que esto no hace que la barra de estado sea completamente transparente, y todavía habrá una superposición "negro desvaído" sobre su barra de estado.

Jeroen Mols
fuente
2
Cuando se usa <item name="android:windowTranslucentStatus">true</item>, hace que Android ponga un fondo negro descolorido debajo de la barra de estado, que no es lo que estoy buscando. ¿Alguna forma de no tener este fondo negro desteñido?
alxscms
1
He intentado muchas cosas, pero no puedo encontrar una manera de eliminar el fondo negro desteñido. Por lo tanto, estoy concluyendo mi investigación diciendo que no es posible en Android (incluso no con el ScrimLayout). Esto tiene sentido, ya que garantiza la legibilidad adecuada de su barra de estado en todo momento. Actualizaré mi respuesta anterior.
Jeroen Mols
Creo que sería muy extraño poder poner un color transparente en la barra de estado, sin poder dibujar detrás de ella. Entiendo por qué dice que tiene sentido que no pueda eliminar este fondo negro desteñido, pero definitivamente no es tan difícil tener el cuidado suficiente para mantener visible el icono de la barra de estado. Aquí hay un artículo de la policía de Android que muestra el uso de una barra de estado transparente androidpolice.com/2014/07/04/… . Trataré de contactar al autor.
alxscms
1
Espero que puedas ponerte en contacto con él. Me estoy interesando mucho en hacer esto también :)
Jeroen Mols
¡Excelente! También actualicé mi respuesta.
Jeroen Mols
9

La solución de Cody Toombs casi me funcionó. No estoy seguro de si esto está relacionado con Xamarin o no, pero ahora tengo una solución aceptable:

Ejemplo

Esta es mi configuración:

Tengo un proyecto de Android en el que hice referencia a los paquetes de Android. V4 y v7. Tengo dos estilos definidos:

valores / 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 apunta a "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>

Y finalmente el código en la Actividad principal:

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

Tenga en cuenta que configuro el indicador DrawsSystemBarBackgrounds, esto hace toda la diferencia

Window.AddFlags (WindowManagerFlags.DrawsSystemBarBackgrounds); 

Pasé mucho tiempo haciendo las cosas bien, de hecho demasiado tiempo. Esperemos que esta respuesta ayude a cualquiera que intente lograr lo mismo.

Gerhard Schreurs
fuente
1
android:windowTranslucentStatusrequiere un nivel de API 19 o superior, ¿cómo es posible que lo esté usando en sus valores / styles.xml mientras tiene un android:minSdkVersion10?
mradzinski
7

La respuesta de @Cody Toombs condujo a un problema que trae el diseño detrás de la barra de navegación. Entonces, lo que encontré es usar esta solución dada por @Kriti

Aquí está el fragmento de código de Kotlin para el mismo:

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

También necesitas agregar

android:fitsSystemWindows="false"

Vista raíz de su diseño.

Kishan Solanki
fuente
3

Tuve el mismo problema, así que creo ImageView que se dibuja detrás de la barra de estado API 19+

Establecer imagen personalizada detrás de la barra de estado 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);

}
Sumit
fuente
2

Puede usar ScrimInsetFrameLayout

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

android: fitsSystemWindows = "true" debería establecerse en el diseño de cañamazo!

Murtaza Khursheed Hussain
fuente
Vi esa clase pero ¿qué pasa si quiero usar un en RelativeLayoutlugar de un FrameLayout?
alxscms
3
usar diseño relativo dentro de un framelayout.
Murtaza Khursheed Hussain
2
Diseños de anidación en diseños definitivamente no es una solución para mí respecto al rendimiento
alxscms
1
El rendimiento de la aplicación depende de muchas cosas que pueden variar. Si no tienes salida, inténtalo. La mejor de las suertes
Murtaza Khursheed Hussain
Entiendo lo que quieres decir, pero debe haber otra solución, de lo contrario podría haber una forma de implementar en cualquier diseño lo que se ha implementado en este diseño de marco personalizado. Pero gracias de todos modos
alxscms
1

Similar a algunas de las soluciones publicadas, pero en mi caso hice la barra de estado transparente y fijé la posición de la barra de acción con un margen negativo

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

Y usé en la barra de herramientas y la vista raíz

android:fitsSystemWindows="true"
jegumi
fuente
1
getStatusBarHeight () no es estándar
Roel
Este método se implementa en la solución de @ mike-milla ... public int getStatusBarHeight () {int result = 0; int resourceId = getResources (). getIdentifier ("status_bar_height", "dimen", "android"); if (resourceId> 0) {result = getResources (). getDimensionPixelSize (resourceId); } resultado devuelto; }
jegumi
Gracias. Lo hice así: AppBarLayout.LayoutParams lp = (AppBarLayout.LayoutParams) toolbar.getLayoutParams (); lp.topMargin + = getStatusBarHeight ();
CoolMind
1

Hay una buena biblioteca StatusBarUtil de @laobie que ayuda a dibujar fácilmente la imagen en StatusBar.

Solo agrega tu build.gradle:

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

Luego en el conjunto de actividades

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

En el diseño

<?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>

Para obtener más información, descargue la demo o clone desde la página de Github y juegue con todas las funciones.

Nota: Soporte KitKat y superior.

¡Espero que ayude a alguien más!

Gueorgui Obregon
fuente
0

Con Android Studio 1.4, el proyecto de plantilla con código de placa de caldera establece el Overlaytema en su AppbarLayout y / o Toolbar. También están configurados para representarse detrás de la barra de estado por fitSystemWindowatributo = verdadero. Esto hará que solo la barra de herramientas se represente directamente debajo de la barra de estado y todo lo demás se mostrará debajo de la barra de herramientas. Por lo tanto, las soluciones proporcionadas anteriormente no funcionarán por sí mismas. Deberá realizar los siguientes cambios.

  • Elimine el tema Superposición o cámbielo a tema no superpuesto para la barra de herramientas.
  • Ponga el siguiente código en su archivo styles-21.xml .

    @android: color / transparente

  • Asigne este tema a la actividad que contiene el cajón de navegación en el archivo AndroidManifest.xml .

Esto hará que el cajón de navegación se muestre detrás de la barra de estado transparente.

Umer Farooq
fuente
0

Todo lo que necesitas hacer es establecer estas propiedades en tu tema

<item name="android:windowTranslucentStatus">true</item>
<item name="android:windowTranslucentNavigation">true</item>
Sudhir singh
fuente
1
Estoy bastante seguro de que esto hará que su diseño quede debajo de los botones de navegación de la interfaz de usuario (dispositivos con navegación en pantalla). Esto hizo que la vista de navegación inferior fuera inaccesible en nuestra aplicación, por lo que abandonamos estas banderas después de probar en un Nexus
EpicPandaForce
0

La respuesta aceptada funcionó para mí usando un CollapsingToolbarLayout. Sin embargo, es importante tener en cuenta que setSytstemUiVisibility()anula cualquier llamada previa a esa función. Entonces, si está utilizando esa función en otro lugar para la misma vista, debe incluir los indicadores View.SYSTEM_UI_FLAG_LAYOUT_STABLEy View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, o se anularán con la nueva llamada.

Este fue mi caso, y una vez que agregué las dos banderas al otro lugar al que estaba llamando setSystemUiVisibility(), la respuesta aceptada funcionó perfectamente.

cpgreen2
fuente
0

Agregaré más información aquí. Los últimos desarrollos de Android han hecho que sea bastante fácil manejar muchos casos en la barra de estado. Las siguientes son mis observaciones de lastyles.xml

  1. Color de fondo : para SDK 21+, como se menciona en muchas respuestas, <item name="android:windowTranslucentStatus">true</item> hará que la barra de estado sea transparente y se muestre frente a la interfaz de usuario. Su actividad ocupará todo el espacio de la parte superior.
  2. Color de fondo : nuevamente, para SDK 21+, <item name="android:statusBarColor">@color/your_color</item>simplemente le dará un color a su barra de estado, sin afectar nada más.

  3. Sin embargo, en dispositivos posteriores (Android M / +), los íconos comenzaron a aparecer en diferentes tonos. El sistema operativo puede dar un tono más oscuro de gris a los iconos para SDK 23 / +, si anula su styles.xmlarchivo en la values-23carpeta y agrega <item name="android:windowLightStatusBar">true</item>.
    De esta manera, proporcionará a su usuario una barra de estado más visible, si su barra de estado tiene un color claro (piense en cómo muchas aplicaciones de Google tienen un fondo claro pero los iconos son visibles allí en un color grisáceo).
    Te sugiero que uses esto, si estás dando color a tu barra de estado a través del punto # 2

  4. En los dispositivos más recientes, SDK 29 / + viene con un tema amplio de luz y oscuridad del sistema, controlable por el usuario. Como desarrolladores, también se supone que debemos anular nuestro archivo de estilo en una nueva values-nightcarpeta, para brindarle al usuario 2 experiencias diferentes.
    Aquí nuevamente, he encontrado que el punto # 2 es efectivo para proporcionar el "color de fondo a la barra de estado". Pero el sistema no estaba cambiando el color de los iconos de la barra de estado para mi aplicación. Dado que mi versión de estilo del día consistía en un tema más claro, esto significa que los usuarios sufrirán una baja visibilidad (iconos blancos sobre un fondo más claro).
    Este problema se puede resolver utilizando el enfoque del punto n. ° 3 o anulando el archivo de estilo en la values-29carpeta y utilizando uno más nuevo api <item name="android:enforceStatusBarContrast">true</item>. Esto aplicará automáticamente el tinte grisáceo a los iconos, si el color de fondo es demasiado claro.

ansh sachdeva
fuente
-1

Aquí está el tema que uso para lograr esto:

<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>
Droid Chris
fuente
1
Hay algunos downvoters extraños. Incluso si una solución fuera adecuada para usted y para alguna otra persona, votarán negativamente en lugar de pasar a otra respuesta.
CoolMind
Todo lo que pido es una explicación. No creo que las personas puedan votar en contra sin una explicación.
Droid Chris
Yo también pienso lo mismo.
CoolMind
Explicaré que la opción de fondo no funciona correctamente en este paquete. Corrige tu respuesta por favor.
Morozov
Hmmm ... ¿en qué versión de Android estás haciendo esto? Estoy usando esta configuración en Android M.
Droid Chris
-3

La solución correcta es cambiar una propiedad en XML debajo de su etiqueta de actividad al siguiente estilo. Solo funciona

  android:theme="@style/Theme.AppCompat.Light.NoActionBar"
satya phani
fuente