Tiroir de navigation semi-transparent sur la barre d'état ne fonctionne pas

86

Je travaille sur un projet Android et j'implémente le tiroir de navigation. Je lis les nouvelles spécifications de conception des matériaux et la liste de contrôle de conception des matériaux .
La spécification indique que le volet coulissant doit flotter au-dessus de tout le reste, y compris la barre d'état, et être semi-transparent sur la barre d'état.

Mon panneau de navigation est au-dessus de la barre d'état mais il n'a aucune transparence. J'ai suivi le code de ce message SO comme suggéré dans le blog des développeurs Google, lien ci-dessus Comment utiliser DrawerLayout pour afficher sur l'ActionBar / Toolbar et sous la barre d'état? .

Ci-dessous ma mise en page 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>

Ci-dessous est mon thème d'applications

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

Ci-dessous, le thème de mes applications 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>

Voici ma méthode 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);
    }

Ci-dessous, une capture d' écran de mon tiroir de navigation montrant que le haut n'est pas semi-transparent

Capture d'écran montrant une vue non transparente sur la barre d'état

Boardy
la source
Publiez une capture d'écran de vos résultats.
Alok Nair
@Boardy avez-vous réussi à le faire fonctionner?
Michele La Ferla
Impossible de définir l'effet transparent dans la barre d'état. Veuillez vous en débarrasser.
Ronak Gadhia

Réponses:

103

L'arrière-plan de votre barre d'état est blanc, l'arrière-plan de votre tiroir LinearLayout. Pourquoi? Vous êtes les paramètres fitsSystemWindows="true"de votre DrawerLayoutet de l' LinearLayoutintérieur. Cela provoque votre LinearLayoutexpansion derrière la barre d'état (qui est transparente). Ainsi, le fond du tiroir fait partie de la barre d'état blanc.

entrez la description de l'image ici
Si vous ne voulez pas que votre tiroir s'étende derrière la barre d'état (vous voulez avoir un arrière-plan semi-transparent pour toute la barre d'état), vous pouvez faire deux choses:

1) Vous pouvez simplement supprimer n'importe quelle valeur d'arrière-plan de votre LinearLayoutet colorer l'arrière-plan de votre contenu à l'intérieur. Ou

2) Vous pouvez supprimer fitsSystemWindows="true"de votre LinearLayout. Je pense que c'est une approche plus logique et plus propre. Vous éviterez également de projeter une ombre sous la barre d'état, là où votre tiroir de navigation ne s'étend pas.

entrez la description de l'image ici
Si vous souhaitez que votre tiroir s'étende derrière la barre d'état et ait une superposition semi-transparente de la taille d'une barre d'état, vous pouvez utiliser a ScrimInsetFrameLayoutcomme conteneur pour le contenu de votre tiroir ( ListView) et définir l'arrière-plan de la barre d'état à l'aide de app:insetForeground="#4000". Bien sûr, vous pouvez changer #4000ce que vous voulez. N'oubliez pas de rester fitsSystemWindows="true"ici!

Ou si vous ne voulez pas superposer votre contenu et n'afficher qu'une couleur unie, vous pouvez simplement définir l'arrière-plan de votre LinearLayoutcomme vous le souhaitez. N'oubliez pas de définir l'arrière-plan de votre contenu séparément!

EDIT: Vous n'avez plus besoin de faire face à tout cela. Veuillez consulter la bibliothèque de support de conception pour une implémentation de tiroir / vue de navigation plus facile.

xip
la source
Merci de votre aide. Désolé pour le retard à rentrer, été très occupé. J'ai configuré une autre prime pour récompenser votre réponse comme je l'avais initialement configurée, mais elle s'est terminée avant que j'aie eu le temps de mettre en œuvre vos suggestions. Je dois attendre 23 heures malheureusement donc je l'ajouterai dès que possible
Boardy
Mise en garde! Avec les options 1 ou 2, assurez-vous de surveiller vos découverts (vous pouvez les vérifier dans les options de développement dans les paramètres du téléphone). Lorsque je ne définissais que l'arrière-plan du contenu à l'intérieur, tout ce qui se trouvait derrière le tiroir était également dessiné. Sinon, bonne réponse, m'a définitivement fait gagner du temps :)
Daiwik Daarun
1
Pouvez-vous expliquer quelle solution nous devons utiliser en utilisant la bibliothèque de support de conception? J'ai quelques problèmes, même avec la réponse publiée par Chris Banes.
mDroidd
29

Tout ce que vous avez à faire est d'utiliser une couleur semi-transparente pour la barre d'état. Ajoutez ces lignes à votre thème v21:

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

N'oubliez pas que la color(ressource) doit toujours être au format #AARRGGBB. Cela signifie que la couleur comprendra également la valeur alpha.

mroczis
la source
Vous êtes l'homme, mais ... Pouvez-vous me dire pourquoi cela ne fonctionne que dans l'activité qui a le tiroir? Les autres, ceux qui ne l'ont pas fait, affichent la barre d'état en gris.
Joaquin Iurchuk
15

Pourquoi ne pas utiliser quelque chose de similaire?

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

Le code ci-dessus utilise la ressource alpha dans le android:backgroundpour pouvoir afficher la transparence dans la barre d'actions.

Il existe d'autres moyens de le faire via le code, comme le montrent d'autres réponses. Ma réponse ci-dessus, fait le nécessaire dans le fichier de mise en page xml, qui à mon avis est facilement éditable.

Michèle La Ferla
la source
4
Pourquoi pas, mais on ne sait pas ce que vous changez et comment cela répond à la question.
rds
définir le séparateur sur des codes alpha transparents et utilisés dans la couleur d'arrière-plan
Michele La Ferla
9

Toutes les réponses mentionnées ici sont trop anciennes et trop longues. La meilleure solution courte qui fonctionne avec la dernière Navigationview est

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

    }
}

cela va changer la couleur de votre barre d'état en transparent lorsque vous ouvrez le tiroir

Maintenant, lorsque vous fermez le tiroir, vous devez à nouveau changer la couleur de la barre d'état en sombre. Vous pouvez donc le faire de cette manière.

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

puis dans la mise en page principale ajoutez une seule ligne ie

            android:fitsSystemWindows="true"

et la disposition de votre tiroir ressemblera à

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

et votre vue de navigation ressemblera à

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

Je l'ai testé et il fonctionne pleinement. J'espère que cela aide quelqu'un. Ce n'est peut-être pas la meilleure approche, mais cela fonctionne bien et est simple à mettre en œuvre. Marquez-le si cela aide. Bon codage :)

Harry Sharma
la source
Merci! Cela m'a fait gagner beaucoup de temps. Cela fonctionne parfaitement avec le dernier NavigationView. Pour ceux qui ne peuvent pas faire fonctionner cela, assurez-vous que vous avez choisi une couleur avec une certaine transparence pour le "colorPrimaryDarktrans", sinon vous ne pouvez pas voir de changement du tout.
Rui
Fonctionne parfaitement, le seul inconvénient est que la barre d'état `` clignote '' lorsque onDrawerClosed est appelé, mais si vous définissez la couleur transparente colorPrimaryDarktrans sur # 05000000, c'est presque imperceptible
Kirill Karmazin
8

Vous devez envelopper la disposition de votre tiroir de navigation dans un ScrimLayout.

A ScrimLayoutdessine essentiellement un rectangle semi-transparent sur la disposition de votre tiroir de navigation. Pour récupérer la taille de l'encart, remplacez simplement fitSystemWindowsvotre fichier ScrimLayout.

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

Remplacement ultérieur onDrawpour dessiner un rectangle semi-transparent.

Un exemple de mise en œuvre peut être trouvé dans la source de l'application Google IO. Ici vous pouvez voir comment il est utilisé dans la mise en page xml.

Markus Salut
la source
5

Si vous voulez que le panneau de navigation se trouve sur la barre d'état et soit semi-transparent sur la barre d'état. Google I / O Android App Source fournit une bonne solution (les fichiers APK du Play Store ne sont pas mis à jour pour la dernière version)

Vous avez d'abord besoin d'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);
    }
}

Ensuite, dans votre mise en page XML, modifiez cette partie

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

Remplacez LinearLayout par ScrimInsetFrameLayout comme ceci

<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
la source
HI, merci pour la réponse .. Je ne trouve pas cela, d'où nous obtenons OnInsetsCallback ... Merci d'avance.
Ashokchakravarthi Nagarajan
pouvez-vous mettre l' ScrimInsetsView_insetForegroundattribut.
reegan29
1
Utilisation android.support.design.internal.ScrimInsetsFrameLayoutde la bibliothèque de support
Roman
4

J'avais une fonctionnalité similaire à implémenter dans mon projet. Et pour rendre mon tiroir transparent, j'utilise simplement la transparence pour les couleurs hexagonales . En utilisant 6 chiffres hexadécimaux, vous avez 2 chiffres hexadécimaux pour chaque valeur de rouge, vert et bleu respectivement. mais si vous mettez deux chiffres supplémentaires (8 chiffres hexadécimaux), vous avez donc ARVB (deux chiffres pour la valeur alpha) ( Regardez ici ).

Voici les valeurs d'opacité hexadécimales: pour les 2 chiffres supplémentaires

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

Par exemple: si vous avez une couleur hexadécimale (# 111111), mettez simplement une des valeurs d'opacité pour obtenir la transparence. comme ceci: (# 11111100)

Mon tiroir ne recouvre pas la barre d'action (comme la vôtre) mais la transparence peut être appliquée dans ces cas également. Voici mon code:

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

Et voici un autre article qui peut vous aider à comprendre les codes alpha en couleurs hexadécimales.

fdsilva
la source
1

Les solutions existantes sont assez dépassées. Voici la dernière solution qui devrait fonctionner parfaitement sur AndroidX ou les bibliothèques de matériaux.

  • Ajoutez android:fitsSystemWindows="true"à la racine la vue de votre mise en page, qui se trouve être DrawerLayout pour votre cas.

    Cela indique à la vue d'utiliser la totalité de l'écran pour la mesure et la mise en page, chevauchant la barre d'état.

  • Ajoutez ce qui suit à votre style XML

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

    windowTranslucentStatus rendra la barre d'état transparente
    windowDrawsSystemBarBackgrounds dit à la barre d'état de dessiner n'importe quoi en dessous au lieu d'être un vide noir.

  • Appelez DrawerLayout.setStatusBarBackground()ouDrawerLayout.setStatusBarBackgroundColor() dans votre activité principale

    Cela indique à DrawerLayout de colorer la zone de la barre d'état.

Brown Smith
la source
0

Au-dessus des bonnes solutions, mais elles n'ont pas fonctionné dans mon cas,

mon cas : barre d'état a déjà une couleur jaune en utilisant des styles, elle n'est pas translucide. et la couleur de mon tiroir de navigation est blanche, maintenant chaque fois que je dessine mon tiroir de navigation, il est toujours derrière la barre d'état et la barre de navigation, car la couleur de la barre de navigation est également définie.

objectif : modifier la barre d'état et la couleur de la barre de navigation lorsque le tiroir de navigation est ouvert et le restaurer lorsqu'il est fermé.

Solution :

        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
la source
0

Toutes les réponses ici sont très compliquées, laissez-moi vous donner un code simple et direct. Sous votre style AppTheme, ajoutez cette ligne de code et vous obtiendrez une barre d'état grise semi-transparente lorsque vous ouvrirez le tiroir.

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

cela le fera fonctionner.

Keshav Bhamaan
la source