La barra de estado semitransparente del cajón de navegación no funciona

86

Estoy trabajando en un proyecto de Android y estoy implementando Navigation Drawer. Estoy leyendo las nuevas especificaciones de diseño de materiales y la lista de verificación de diseño de materiales .
La especificación dice que el panel deslizable debe flotar sobre todo lo demás, incluida la barra de estado, y ser semitransparente sobre la barra de estado.

Mi panel de navegación está sobre la barra de estado pero no tiene transparencia. He seguido el código de esta publicación de SO como se sugiere en el sitio del blog de desarrolladores de Google, enlace arriba ¿Cómo uso DrawerLayout para mostrar sobre ActionBar / Toolbar y debajo de la barra de estado? .

A continuación se muestra mi diseño XML

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <android.support.v7.widget.Toolbar
            android:id="@+id/my_awesome_toolbar"
            android:layout_height="wrap_content"
            android:layout_width="match_parent"
            android:minHeight="?attr/actionBarSize"
            android:background="@color/appPrimaryColour" />
    </LinearLayout>
    <LinearLayout android:id="@+id/linearLayout"
        android:layout_width="304dp"
        android:layout_height="match_parent"
        android:layout_gravity="left|start"
        android:fitsSystemWindows="true"
        android:background="#ffffff">
        <ListView android:id="@+id/left_drawer"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:choiceMode="singleChoice"></ListView>
    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

A continuación se muestra el tema de mi aplicación

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/appPrimaryColour</item>
        <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
        <item name="colorAccent">@color/appPrimaryColour</item>
        <item name="windowActionBar">false</item>
        <item name="windowActionModeOverlay">true</item>

    </style>

A continuación se muestra el tema de mi aplicación v21

<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="colorPrimary">@color/appPrimaryColour</item>
    <item name="colorPrimaryDark">@color/appPrimaryColourDark</item>
    <item name="colorAccent">@color/appPrimaryColour</item>
    <item name="windowActionBar">false</item>
    <item name="windowActionModeOverlay">true</item>
    <item name="android:windowDrawsSystemBarBackgrounds">true</item>
    <item name="android:statusBarColor">@android:color/transparent</item>
</style>

A continuación se muestra mi método onCreate

protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
    setSupportActionBar(toolbar);

    mDrawerLayout = (DrawerLayout)findViewById(R.id.my_drawer_layout);
    mDrawerList = (ListView)findViewById(R.id.left_drawer);

    mDrawerLayout.setStatusBarBackgroundColor(
        getResources().getColor(R.color.appPrimaryColourDark));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
    {
        LinearLayout linearLayout = 
            (LinearLayout)findViewById(R.id.linearLayout);
        linearLayout.setElevation(30);
    }

A continuación se muestra una captura de pantalla de mi cajón de navegación que muestra que la parte superior no es semitransparente

Captura de pantalla que muestra no transparente sobre la barra de estado

Boardy
fuente
Publica una captura de pantalla de tus resultados.
Alok Nair
@Boardy, ¿has logrado que funcione?
Michele La Ferla
No se puede configurar el efecto transparente en la barra de estado. Por favor, deshazte de él.
Ronak Gadhia

Respuestas:

103

El fondo de la barra de estado es blanco, el fondo de su cajón LinearLayout. ¿Por qué? Son ajustes fitsSystemWindows="true"para usted DrawerLayouty su LinearLayoutinterior. Esto hace LinearLayoutque se expanda detrás de la barra de estado (que es transparente). Por lo tanto, hacer que el fondo de la parte del cajón de la barra de estado sea blanco.

ingrese la descripción de la imagen aquí
Si no desea que su cajón se extienda detrás de la barra de estado (desea tener un fondo semitransparente para toda la barra de estado), puede hacer dos cosas:

1) Simplemente puede eliminar cualquier valor de fondo de su LinearLayouty colorear el fondo de su contenido dentro de él. O

2) Puede eliminar fitsSystemWindows="true"de su LinearLayout. Creo que este es un enfoque más lógico y más limpio. También evitará que se proyecte una sombra debajo de la barra de estado, donde su cajón de navegación no se extiende.

ingrese la descripción de la imagen aquí
Si desea que su cajón se extienda detrás de la barra de estado y tenga una superposición semitransparente del tamaño de la barra de estado, puede usar a ScrimInsetFrameLayoutcomo contenedor para el contenido del cajón ( ListView) y establecer el fondo de la barra de estado usando app:insetForeground="#4000". Por supuesto, puede cambiar #4000a lo que desee. ¡No olvides quedarte fitsSystemWindows="true"aquí!

O si no desea superponer su contenido y solo mostrar un color sólido, puede configurar el fondo de su imagen LinearLayoutcomo desee. Sin embargo, ¡no olvide configurar el fondo de su contenido por separado!

EDITAR: Ya no necesitas lidiar con nada de esto. Consulte la Biblioteca de soporte de diseño para una implementación de vista / panel de navegación más fácil.

xip
fuente
Gracias por tu ayuda. Perdón por la demora en regresar, he estado muy ocupado. Configuré otra recompensa para recompensar su respuesta como la configuré originalmente, pero terminó antes de que tuviera tiempo de implementar sus sugerencias. Desafortunadamente, tengo que esperar 23 horas, así que lo
agregaré
¡Precaución! Con las opciones 1 o 2, asegúrese de vigilar sus sobregiros (puede verificarlos en las opciones de desarrollo en la configuración del teléfono). Cuando solo puse el fondo del contenido dentro, todo lo que estaba detrás del cajón también se dibujó. De lo contrario, una gran respuesta, definitivamente me salvó algo de tiempo :)
Daiwik Daarun
1
¿Puede explicar qué solución necesitamos utilizar utilizando la biblioteca de soporte de diseño? Tengo algunos problemas, incluso con la respuesta que publicó Chris Banes.
mDroidd
29

Todo lo que necesita hacer es usar un color semitransparente para la barra de estado. Agregue estas líneas a su tema v21:

<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="android:statusBarColor">@color/desired_color</item>

No olvide que el color(recurso) siempre debe tener el formato #AARRGGBB. Esto significa que el color también incluirá el valor alfa.

mroczis
fuente
Tú eres el hombre, pero ... ¿Puedes decirme por qué esto funciona solo en la Actividad que tiene el Cajón? Los demás, los que no lo han hecho, muestran la barra de estado en gris.
Joaquin Iurchuk
15

¿Por qué no usar algo similar a esto?

<android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >

    <FrameLayout
            android:id="@+id/content_frame"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    <ListView
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="0dp"
            android:background="#80111111"/>
</android.support.v4.widget.DrawerLayout>

El código anterior usa el recurso alfa en el android:backgroundpara poder mostrar transparencia dentro de la barra de acciones.

Hay otras formas de hacer esto a través del código, como muestran otras respuestas. Mi respuesta anterior, hace lo necesario en el archivo de diseño xml, que en mi opinión se edita fácilmente.

Michele La Ferla
fuente
4
Por qué no, pero no está claro qué está cambiando y cómo responde esto a la pregunta.
RDS
establezca el divisor en códigos alfa transparentes y usados ​​en el color de fondo
Michele La Ferla
9

Todas las respuestas mencionadas aquí son demasiado antiguas y extensas. La mejor y más corta solución que funciona con la última Navigationview es

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
    super.onDrawerSlide(drawerView, slideOffset);

    try {
        //int currentapiVersion = android.os.Build.VERSION.SDK_INT;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
            // Do something for lollipop and above versions

        Window window = getWindow();

        // clear FLAG_TRANSLUCENT_STATUS flag:
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

        // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

        // finally change the color to any color with transparency

         window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDarktrans));}

    } catch (Exception e) {

        Crashlytics.logException(e);

    }
}

esto va a cambiar el color de la barra de estado a transparente cuando abras el cajón

Ahora, cuando cierre el cajón, deberá cambiar el color de la barra de estado nuevamente a oscuro, para que pueda hacerlo de esta manera.

@Override
public void onDrawerClosed(View drawerView) {
   super.onDrawerClosed(drawerView);
    try {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            // Do something for lollipop and above versions

            Window window = getWindow();

            // clear FLAG_TRANSLUCENT_STATUS flag:
            window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);

            // add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
            window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);

            // finally change the color again to dark
            window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark));
        }
    } catch (Exception e) {
        Crashlytics.logException(e);
    }
}

y luego en el diseño principal agregue una sola línea, es decir

            android:fitsSystemWindows="true"

y el diseño de su cajón se verá como

            <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:fitsSystemWindows="true"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

y su vista de navegación se verá como

    <android.support.design.widget.NavigationView
        android:id="@+id/navigation_view"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/drawer"
        />

Lo he probado y funciona completamente. Espero que ayude a alguien. Puede que este no sea el mejor enfoque, pero funciona sin problemas y es fácil de implementar. Márquelo si ayuda. Feliz codificación :)

Harry Sharma
fuente
¡Gracias! Esto me ahorró mucho tiempo. Funciona perfectamente con la última NavigationView. Para cualquiera que no pueda hacer que esto funcione, asegúrese de elegir un color con algo de transparencia para el "colorPrimaryDarktrans", de lo contrario, no verá ningún cambio en absoluto.
Rui
Funciona perfectamente, la única desventaja es que la barra de estado 'parpadea' cuando se llama a onDrawerClosed, pero si configura el color transparente colorPrimaryDarktrans en # 05000000 es casi imperceptible
Kirill Karmazin
8

Debe envolver el diseño del cajón de navegación dentro de un archivo ScrimLayout.

ScrimLayoutBásicamente, A dibuja un rectángulo semitransparente sobre el diseño del cajón de navegación. Para recuperar el tamaño del recuadro, simplemente anule fitSystemWindowssu ScrimLayout.

@Override
protected boolean fitSystemWindows(Rect insets) {
    mInsets = new Rect(insets);
    return true;
}

Posteriormente anule onDrawpara dibujar un rectángulo semitransparente.

Puede encontrar una implementación de ejemplo en la fuente de la aplicación Google IO. Aquí puede ver cómo se usa en el diseño xml.

Markus Hola
fuente
5

Si desea que el panel de navegación esté sobre la barra de estado y sea semitransparente sobre la barra de estado. Google I / O Android App Source proporciona una buena solución (los APK en Play Store no se actualizan a la última versión)

Primero necesitas un ScrimInsetFrameLayout

/*
* Copyright 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome
* (status and navigation bars, overlay action bars).
*/
public class ScrimInsetsFrameLayout extends FrameLayout {
    private Drawable mInsetForeground;

    private Rect mInsets;
    private Rect mTempRect = new Rect();
    private OnInsetsCallback mOnInsetsCallback;

    public ScrimInsetsFrameLayout(Context context) {
        super(context);
        init(context, null, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context, attrs, defStyle);
    }

    private void init(Context context, AttributeSet attrs, int defStyle) {
        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ScrimInsetsView, defStyle, 0);
        if (a == null) {
            return;
        }
        mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsView_insetForeground);
        a.recycle();

        setWillNotDraw(true);
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        mInsets = new Rect(insets);
        setWillNotDraw(mInsetForeground == null);
        ViewCompat.postInvalidateOnAnimation(this);
        if (mOnInsetsCallback != null) {
            mOnInsetsCallback.onInsetsChanged(insets);
        }
        return true; // consume insets
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);

        int width = getWidth();
        int height = getHeight();
        if (mInsets != null && mInsetForeground != null) {
            int sc = canvas.save();
            canvas.translate(getScrollX(), getScrollY());

            // Top
            mTempRect.set(0, 0, width, mInsets.top);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Bottom
            mTempRect.set(0, height - mInsets.bottom, width, height);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Left
            mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            // Right
            mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom);
            mInsetForeground.setBounds(mTempRect);
            mInsetForeground.draw(canvas);

            canvas.restoreToCount(sc);
        }
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(this);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mInsetForeground != null) {
            mInsetForeground.setCallback(null);
        }
    }

    /**
     * Allows the calling container to specify a callback for custom processing when insets change (i.e. when
     * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on
     * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set
     * clipToPadding to false.
     */
    public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) {
        mOnInsetsCallback = onInsetsCallback;
    }

    public static interface OnInsetsCallback {
        public void onInsetsChanged(Rect insets);
    }
}

Luego, en su diseño XML cambie esta parte

<LinearLayout android:id="@+id/linearLayout"
    android:layout_width="304dp"
    android:layout_height="match_parent"
    android:layout_gravity="left|start"
    android:fitsSystemWindows="true"
    android:background="#ffffff">
    <ListView android:id="@+id/left_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"></ListView>
</LinearLayout>

Cambie LinearLayout a su ScrimInsetFrameLayout así

<com.boardy.util.ScrimInsetFrameLayout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/linearLayout"
    android:layout_width="304dp"
    android:layout_height="match_parent"
    android:layout_gravity="left|start"
    android:fitsSystemWindows="true"
    app:insetForeground="#4000">
    <ListView android:id="@+id/left_drawer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:choiceMode="singleChoice"></ListView>
</com.boardy.util.ScrimInsetFrameLayout>
skyfishjy
fuente
Hola, gracias por la respuesta .. No puedo encontrar eso, de donde obtenemos OnInsetsCallback ... Gracias de antemano.
Ashokchakravarthi Nagarajan
puedes poner el ScrimInsetsView_insetForegroundatributo.
reegan29
1
Uso android.support.design.internal.ScrimInsetsFrameLayoutde la biblioteca de apoyo
Roman
4

Tenía una característica similar para implementar en mi proyecto. Y para que mi cajón sea transparente, solo uso la transparencia para colores hexadecimales . Con 6 dígitos hexadecimales, tiene 2 dígitos hexadecimales para cada valor de rojo, verde y azul, respectivamente. pero si pones dos dígitos adicionales (8 dígitos hexadecimales), entonces tienes ARGB (dos dígitos para el valor alfa) ( mira aquí ).

Estos son los valores de opacidad hexadecimal: para los 2 dígitos adicionales

100%  FF
95%  F2
90%  E6
85%  D9
80%  CC
75%  BF
70%  B3
65%  A6
60%  99
55%  8C
50%  80
45%  73
40%  66
35%  59
30%  4D
25%  40
20%  33
15%  26
10%  1A
5%  0D
0%  00

Por ejemplo: si tiene un color hexadecimal (# 111111) simplemente coloque uno de los valores de opacidad para obtener transparencia. así: (# 11111100)

Mi cajón no cubre la barra de acción (como la tuya) pero la transparencia también se puede aplicar en estos casos. Aquí está mi código:

     <ListView
          android:id="@+id/left_drawer"
          android:layout_width="240dp"
          android:layout_height="match_parent"
          android:layout_gravity="start"
          android:background="#11111100"
          android:choiceMode="singleChoice"
          android:divider="@android:color/transparent"
          android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>

Y aquí hay otro artículo que puede ayudarlo a comprender los códigos alfa en colores hexadecimales.

fdsilva
fuente
1

Las soluciones existentes están bastante desactualizadas. Aquí está la última solución que debería funcionar perfectamente en AndroidX o bibliotecas de materiales.

  • Agregue android:fitsSystemWindows="true"a la vista raíz de su diseño, que resulta ser DrawerLayout para su caso.

    Esto le dice a la Vista que use toda la pantalla para medir y diseñar, superponiéndose con la barra de estado.

  • Agregue lo siguiente a su estilo XML

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

    windowTranslucentStatushará que la barra de estado sea transparente
    windowDrawsSystemBarBackgroundsle dice a la barra de estado que dibuje cualquier cosa debajo de ella en lugar de ser un vacío negro.

  • Llama DrawerLayout.setStatusBarBackground()o DrawerLayout.setStatusBarBackgroundColor()en tu actividad principal

    Esto le dice a DrawerLayout que coloree el área de la barra de estado.

Brown Smith
fuente
0

Las anteriores son buenas soluciones, pero no funcionaron en mi caso,

mi caso: la barra de estado tiene un conjunto de color amarillo que ya usa estilos, no es translúcido. y el color de mi cajón de navegación es blanco, ahora cada vez que dibujo mi cajón de navegación siempre está detrás de la barra de estado y la barra de navegación también, ya que el color de la barra de navegación también está configurado.

Objetivo: cambiar la barra de estado y el color de la barra de navegación cuando se abre el cajón de navegación y restaurarlo cuando se cierra.

solucion:

        binding.drawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() 
        {
        @Override
        public void onDrawerSlide(@NonNull View drawerView, float slideOffset) {
        }

        @Override
        public void onDrawerOpened(@NonNull View drawerView) {
            getWindow().setStatusBarColor(getResources().getColor(R.color.forground));
            getWindow().setNavigationBarColor(getResources().getColor(R.color.forground));
        }

        @Override
        public void onDrawerClosed(@NonNull View drawerView) {
            getWindow().setStatusBarColor(getResources().getColor(R.color.yellow));
            getWindow().setNavigationBarColor(getResources().getColor(R.color.yellow));
        }

        @Override
        public void onDrawerStateChanged(int newState) {
        }
    });
Abhishek Garg
fuente
0

Todas las respuestas aquí son muy complicadas, déjame darte un código simple y directo. En su estilo AppTheme, agregue esta línea de código y obtendrá una barra de estado gris semitransparente cuando abra el cajón.

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

esto hará que funcione.

Keshav Bhamaan
fuente