Il cassetto di navigazione semitrasparente sulla barra di stato non funziona


86

Sto lavorando al progetto Android e sto implementando il Navigation Drawer. Sto leggendo le nuove specifiche di Material Design e la Checklist di Material Design .
Le specifiche dicono che il riquadro a scorrimento dovrebbe essere sospeso sopra tutto il resto, inclusa la barra di stato, ed essere semitrasparente sulla barra di stato.

Il mio pannello di navigazione si trova sulla barra di stato ma non ha alcuna trasparenza. Ho seguito il codice da questo post SO come suggerito nello spot del blog degli sviluppatori di Google, link sopra Come posso utilizzare DrawerLayout per visualizzare sopra la ActionBar / Toolbar e sotto la barra di stato? .

Di seguito è riportato il mio layout 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>

Di seguito è riportato il tema delle mie app

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

Di seguito è riportato il tema della mia app 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>

Di seguito è riportato il mio metodo 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);
    }

Di seguito è riportato uno screenshot del mio cassetto di navigazione che mostra che la parte superiore non è semitrasparente

Screenshot che mostra non trasparente sulla barra di stato


Pubblica uno screenshot dei tuoi risultati.
Alok Nair

@ Boardy sei riuscito a farlo funzionare?
Michele La Ferla

Impossibile impostare l'effetto Trasparente nella barra di stato. Eliminalo.
Ronak Gadhia

Risposte:


103

Lo sfondo della barra di stato è bianco, lo sfondo del tuo cassetto LinearLayout. Perché? Sei le impostazioni fitsSystemWindows="true"per il tuo DrawerLayoute per il suo LinearLayoutinterno. Ciò fa sì LinearLayoutche si espanda dietro la barra di stato (che è trasparente). Quindi, rendere bianco lo sfondo per la parte del cassetto della barra di stato.

inserisci qui la descrizione dell'immagine
Se non vuoi che il tuo cassetto si estenda dietro la barra di stato (vuoi avere uno sfondo semitrasparente per l'intera barra di stato), puoi fare due cose:

1) Puoi semplicemente rimuovere qualsiasi valore di sfondo dal tuo LinearLayoute colorare lo sfondo del tuo contenuto al suo interno. O

2) Puoi rimuovere fitsSystemWindows="true"dal tuo file LinearLayout. Penso che questo sia un approccio più logico e più pulito. Eviterete anche di proiettare un'ombra sotto la barra di stato, dove il cassetto di navigazione non si estende.

inserisci qui la descrizione dell'immagine
Se desideri che il tuo cassetto si estenda dietro la barra di stato e abbia una sovrapposizione semitrasparente della dimensione della barra di stato, puoi usare ScrimInsetFrameLayoutcome contenitore per il contenuto del cassetto ( ListView) e impostare lo sfondo della barra di stato usando app:insetForeground="#4000". Ovviamente puoi cambiare #4000tutto quello che vuoi. Non dimenticare di restare fitsSystemWindows="true"qui!

Oppure, se non vuoi sovrapporre i tuoi contenuti e visualizzare solo un colore solido, puoi semplicemente impostare lo sfondo del tuo LinearLayoutsu tutto ciò che desideri. Non dimenticare di impostare separatamente lo sfondo dei tuoi contenuti!

EDIT: non hai più bisogno di occuparti di tutto questo. Si prega di consultare la libreria di supporto alla progettazione per un'implementazione del cassetto di navigazione / vista più semplice.


Grazie per l'aiuto. Ci scusiamo per il ritardo nel rientro, sono stato impegnato. Ho impostato un'altra taglia per premiare la tua risposta come avevo inizialmente impostato, ma è terminata prima che avessi il tempo di implementare i tuoi suggerimenti. Sfortunatamente devo aspettare 23 ore, quindi lo aggiungerò appena possibile
Boardy

Attenzione! Con le opzioni 1 o 2, assicurati di controllare i tuoi overdraw (puoi controllarli nelle opzioni di sviluppo nelle impostazioni del telefono). Quando ho impostato solo lo sfondo del contenuto all'interno di tutto ciò che è dietro il cassetto, veniva disegnato anche. Altrimenti ottima risposta, sicuramente mi ha risparmiato un po 'di tempo :)
Daiwik Daarun

1
Puoi per favore spiegare quale soluzione dobbiamo usare usando la libreria di supporto alla progettazione? Ho dei problemi, anche con la risposta pubblicata da Chris Banes.
mDroidd

29

Tutto quello che devi fare è usare un colore semitrasparente per la barra di stato. Aggiungi queste righe al tuo tema v21:

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

Non dimenticare che la color(risorsa) deve essere sempre nel formato #AARRGGBB. Ciò significa che il colore includerà anche il valore alfa.


Sei l'uomo, ma ... Puoi dirmi perché funziona solo nell'attività che ha il cassetto? Gli altri, quelli che non lo hanno, mostrano la barra di stato grigia.
Joaquin Iurchuk

15

Perché non usare qualcosa di simile a questo?

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

Il codice sopra usa la risorsa alpha in android:backgroundper poter mostrare la trasparenza all'interno della barra delle azioni.

Ci sono altri modi per farlo tramite il codice, come mostrano altre risposte. La mia risposta sopra, fa il necessario nel file di layout xml, che a mio parere è facilmente modificabile.


4
Perché no, ma non è chiaro cosa stai cambiando e come questo sta rispondendo alla domanda.
rds

imposta il divisore su codici alfa trasparenti e utilizza il colore di sfondo
Michele La Ferla

9

Tutte le risposte qui menzionate sono troppo vecchie e lunghe. La soluzione migliore e breve che funziona con l'ultima Navigationview è

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

    }
}

questo cambierà il colore della barra di stato in trasparente quando apri il cassetto

Ora quando chiudi il cassetto devi cambiare di nuovo il colore della barra di stato in scuro, quindi puoi farlo in questo modo.

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

e quindi nel layout principale aggiungi una singola riga, ad es

            android:fitsSystemWindows="true"

e il layout del tuo cassetto sarà simile

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

e la tua visualizzazione di navigazione sarà simile

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

L'ho testato e funziona perfettamente, spero che aiuti qualcuno. Questo potrebbe non essere l'approccio migliore ma funziona senza problemi ed è semplice da implementare. Segnalo se aiuta. Buona codifica :)


Grazie! Questo mi ha fatto risparmiare molto tempo. Funziona perfettamente con l'ultimo NavigationView. Per chiunque non possa farlo funzionare, assicurati di aver scelto un colore con una certa trasparenza per "colorPrimaryDarktrans", altrimenti non puoi vedere alcun cambiamento.
Rui

Funziona perfettamente, l'unico svantaggio è che la barra di stato "lampeggia" quando viene chiamato onDrawerClosed, ma se imposti il ​​colore trasparente colorPrimaryDarktrans su # 05000000 è quasi impercettibile
Kirill Karmazin

8

Devi avvolgere il layout del cassetto di navigazione all'interno di un file ScrimLayout .

A ScrimLayoutdisegna fondamentalmente un rettangolo semitrasparente sul layout del cassetto di navigazione. Per recuperare la dimensione del riquadro, sovrascrivi semplicemente fitSystemWindowsnel tuo ScrimLayout.

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

Override in seguito onDraw l' per disegnare un rettangolo semitrasparente.

Un'implementazione di esempio può essere trovata nell'origine dell'app Google IO. Qui puoi vedere come viene utilizzato nel layout xml.


5

Se vuoi che il pannello di navigazione si trovi sopra la barra di stato e sia semitrasparente sopra la barra di stato. Google I / O Android App Source fornisce una buona soluzione (gli APK nel Play Store non vengono aggiornati alla versione duratura)

Per prima cosa hai bisogno di uno 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);
    }
}

Quindi, nel tuo layout XML cambia questa 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>

Cambia LinearLayout al tuo ScrimInsetFrameLayout in questo modo

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

Ciao, grazie per la risposta .. Non riesco a trovarla, da dove otteniamo OnInsetsCallback ... Grazie in anticipo.
Ashokchakravarthi Nagarajan

puoi mettere l' ScrimInsetsView_insetForegroundattributo.
reegan29

1
Utilizzare android.support.design.internal.ScrimInsetsFrameLayoutdalla libreria di supporto
Roman

4

Avevo una funzionalità simile da implementare nel mio progetto. E per rendere trasparente il mio cassetto, uso solo la trasparenza per i colori esadecimali . Utilizzando 6 cifre esadecimali, hai 2 cifre esadecimali per ciascun valore rispettivamente di rosso, verde e blu. ma se inserisci due cifre aggiuntive (8 cifre esadecimali), quindi hai ARGB (due cifre per il valore alfa) ( guarda qui ).

Ecco i valori esadecimali di opacità: per le 2 cifre aggiuntive

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

Ad esempio: se hai un colore esadecimale (# 111111) metti uno dei valori di opacità per ottenere la trasparenza. come questo: (# 11111100)

Il mio drawer non copre la barra delle azioni (come la tua) ma la trasparenza può essere applicata anche in questi casi. Ecco il mio codice:

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

Ed ecco un altro articolo che può aiutarti a capire i codici alfa in colori esadecimali.


1

Le soluzioni esistenti sono abbastanza obsolete. Ecco l'ultima soluzione che dovrebbe funzionare perfettamente su AndroidX o sulle librerie di materiali.

  • Aggiungi android:fitsSystemWindows="true"alla vista principale del tuo layout, che è DrawerLayout per il tuo caso.

    Questo indica alla vista di utilizzare l'intero schermo per misure e layout, sovrapponendosi alla barra di stato.

  • Aggiungi quanto segue al tuo stile XML

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

    windowTranslucentStatusrenderà la barra di stato trasparente
    windowDrawsSystemBarBackgroundsdice alla barra di stato di disegnare qualsiasi cosa sotto di essa invece di essere un vuoto nero.

  • Chiama DrawerLayout.setStatusBarBackground()o DrawerLayout.setStatusBarBackgroundColor()nella tua attività principale

    Questo dice a DrawerLayout di colorare l'area della barra di stato.


0

Sopra quelle buone soluzioni, ma non hanno funzionato nel mio caso,

il mio caso: la barra di stato ha un colore giallo impostato già utilizzando stili, non è traslucida. e il colore del mio cassetto di navigazione è bianco, ora ogni volta che disegno il mio cassetto di navigazione è sempre dietro la barra di stato e anche la barra di navigazione, poiché anche il colore della barra di navigazione è impostato.

obiettivo: modificare la barra di stato e il colore della barra di navigazione all'apertura del riquadro di navigazione e ripristinarlo quando viene chiuso.

soluzione:

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

0

Tutte le risposte qui sono molto complicate, lascia che ti dia un codice semplice e diretto. Sotto il tuo stile AppTheme, aggiungi questa riga di codice e otterrai una barra di stato semi trasparente grigia quando apri il cassetto.

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

questo lo farà funzionare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.