«Élévation» Android ne montrant pas d'ombre


273

J'ai un ListView, et avec chaque élément de la liste, je veux qu'il montre une ombre en dessous. J'utilise la nouvelle fonction d'élévation d'Android Lollipop pour définir un Z sur la vue que je veux projeter une ombre, et je le fais déjà efficacement avec l'ActionBar (techniquement une barre d'outils dans Lollipop). J'utilise l'élévation de Lollipop, mais pour une raison quelconque, il n'affiche pas d'ombre sous les éléments de la liste. Voici comment la disposition de chaque élément de liste est configurée:

<?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"
    android:orientation="vertical"
    style="@style/block"
    android:gravity="center"
    android:layout_gravity="center"
    android:background="@color/lightgray"
    >

    <RelativeLayout
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_marginLeft="40dp"
        android:layout_marginRight="40dp"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:elevation="30dp"
        >

        <ImageView
            android:id="@+id/documentImageView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop" />

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/alphared"
            android:layout_alignParentBottom="true" >

            <appuccino.simplyscan.Extra.CustomTextView
                android:id="@+id/documentName"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                app:typeface="light"
                android:paddingLeft="16dp"
                android:paddingTop="8dp"
                android:paddingBottom="4dp"
                android:singleLine="true"
                android:text="New Document"
                android:textSize="27sp"/>

            <appuccino.simplyscan.Extra.CustomTextView
                android:id="@+id/documentPageCount"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textColor="@color/white"
                app:typeface="italic"
                android:paddingLeft="16dp"
                android:layout_marginBottom="16dp"
                android:text="1 page"
                android:textSize="20sp"/>

        </LinearLayout>

    </RelativeLayout>

</RelativeLayout>

Cependant, voici comment il affiche l'élément de liste, sans ombre: entrez la description de l'image ici

J'ai également essayé ce qui suit en vain:

  1. Définissez l'élévation sur ImageView et TextViews eux-mêmes au lieu de la disposition parent.
  2. Applique un arrière-plan à ImageView.
  3. TranslationZ utilisé à la place de l'élévation.

J'ai essayé votre mise en page (sans vues personnalisées) et montré l'ombre dans mon téléphone, pourriez-vous partager un projet minimal qui reproduit le problème?
rnrneverdies

1
doublon possible de l' ombre du bouton Android L FAB
naveejr

Réponses:


384

Je joue avec les ombres sur Lollipop depuis un moment et voici ce que j'ai trouvé:

  1. Il semble que ViewGrouples limites d' un parent coupent l'ombre de ses enfants pour une raison quelconque; et
  2. les ombres définies par android:elevationsont coupées par les Viewlimites de 's, et non par les limites étendues à travers la marge;
  3. la bonne façon d'obtenir une vue enfant pour montrer l'ombre est de définir un remplissage sur le parent et de définir android:clipToPadding="false"sur ce parent.

Voici ma suggestion basée sur ce que je sais:

  1. Définissez votre niveau supérieur RelativeLayoutpour avoir un rembourrage égal aux marges que vous avez définies sur la disposition relative que vous souhaitez afficher l'ombre;
  2. mis android:clipToPadding="false"sur le même RelativeLayout;
  3. Supprimez la marge de celle RelativeLayoutqui a également défini l'élévation;
  4. [MODIFIER] vous devrez peut-être également définir une couleur d'arrière-plan non transparente sur la mise en page enfant nécessitant une élévation.

À la fin de la journée, votre disposition relative de niveau supérieur devrait ressembler à ceci:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    style="@style/block"
    android:gravity="center"
    android:layout_gravity="center"
    android:background="@color/lightgray"
    android:paddingLeft="40dp"
    android:paddingRight="40dp"
    android:paddingTop="20dp"
    android:paddingBottom="20dp"
    android:clipToPadding="false"
    >

La disposition relative intérieure devrait ressembler à ceci:

<RelativeLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:background="[some non-transparent color]"
    android:elevation="30dp"
    >

8
Merci pour cela! J'ai également trouvé que android: clipChildren = "false" était utile lorsqu'il était appliqué à la disposition relative des parents.
blaffie

1
Heureux d'aider @blaffie!
Justin Pollard

214
C'est tellement ennuyeux que Google produit un tel code de mauvaise qualité. Nous devrons tenir compte de ces bogues du framework pendant des années.
miguel

8
Google dit seulement (hélas): "Les ombres sont dessinées par le parent de la vue élevée, et donc soumises à un écrêtage de vue standard, écrêtées par le parent par défaut. ".
John

5
Dans mon cas, c'était la couleur transparente. Ok, les choses transparentes ne projettent pas d'ombres ... haha
Ferran Maylinch

286

Si vous avez une vue sans arrière-plan, cette ligne vous aidera

android:outlineProvider="bounds"

Par défaut, l'ombre est déterminée par l'arrière-plan de la vue, donc s'il n'y a pas d'arrière-plan, il n'y aura pas d'ombre également.


11
Quelle chose étrange, Preview a montré l'élévation, mais pas le vrai appareil. Merci, celui-ci a résolu le problème.
Ioane Sharvadze

Fonctionne pour API niveau 21 et supérieur
Pantelis Ieronimakis

10
Ce genre de travail pour moi, mais a donné une bordure diagonale sur les côtés lorsqu'il est appliqué à une visualisation de texte. Définir l'arrière-plan sur une couleur (identique à la couleur d'arrière-plan des parents) a mieux fonctionné.
Gober

4
Cela s'applique également si votre arrière-plan est personnalisé et n'en a pas <solid>.
David Lord

Cela peut être utilisé à l'envers. Lorsque vous voulez un arrière-plan non transparent avec élévation et que vous ne voulez pas d'ombre. Réglez-le simplement sur none. Merci!
Odys

101

Apparemment, vous ne pouvez pas simplement définir une élévation sur une vue et la faire apparaître. Vous devez également spécifier un arrière-plan.

Les lignes suivantes ajoutées à mon LinearLayout ont finalement montré une ombre:

android:background="@android:color/white"
android:elevation="10dp"

C'était inattendu. J'ai défini ImageView avec src et recherchais une solution. Je vous remercie.
Andrew Grow

47

une autre chose que vous devez savoir, les ombres ne s'afficheront pas si vous avez cette ligne dans le manifeste:

android: hardwareAccelerated = "false"

J'ai essayé toutes les choses suggérées, mais cela n'a fonctionné pour moi que lorsque j'ai supprimé la ligne, la raison pour laquelle je l'avais était parce que mon application fonctionne avec un certain nombre d'images bitmap et qu'elles provoquaient le blocage de l'application.


1
Cela ne résout pas le problème, si vous avez besoin que ce drapeau soit présent.
Clive Jefferies

Merci!! J'ai passé une journée à essayer d'élever l'AppBar et j'ai trouvé le problème lorsque j'ai vérifié le manifeste de cet indicateur d'activité
ir2pid

1
J'ai essayé toutes les solutions possibles, mais rien n'a fonctionné pour moi. Ces solutions ont fonctionné. Merci. Besoin également android:clipToPadding="false"avec cette solution.
Chirag Savsani

29

Si vous avez une vue sans arrière-plan, cette ligne vous aidera

android:outlineProvider="bounds"

Si vous avez une vue en arrière-plan, cette ligne vous aidera

android:outlineProvider="paddedBounds"

6
Cette solution est la seule qui fonctionne pour moi. Merci
Oleh Liskovych

4
Cela fonctionne sauf si vous avez un rayon sur l'arrière-plan de votre vue, auquel cas l'ombre apparaîtra comme rectangulaire, mais paddedBounds fonctionne pour une vue avec un arrière-plan.
Trevor Hart

android:outlineProvider="paddedBounds"cette ligne a fonctionné pour moi. Je mets Selector Drawable.
Chirag Savsani

1
Lorsque j'ai utilisé cela, l'ombre est dessinée complètement à l'intérieur de la vue plutôt qu'à l'extérieur, ce qui n'est pas ce que je veux.
androidguy


12

Ugh, viens de passer une heure à essayer de comprendre cela. Dans mon cas, j'avais un arrière-plan, mais il était réglé sur une couleur. Cela ne suffit pas, vous devez définir l'arrière-plan de la vue sur un dessin.

par exemple, cela n'aura pas d'ombre:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="165dp"
    android:background="@color/ight_grey"
    android:elevation="20dp"
    android:orientation="vertical"
    />

mais ce sera

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="165dp"
    android:background="@drawable/selector_grey"
    android:elevation="20dp"
    android:orientation="vertical"
    />

EDIT: ont également découvert que si vous utilisez un sélecteur comme arrière-plan, si vous n'avez pas le coin défini, l'ombre n'apparaîtra pas dans la fenêtre d'aperçu mais apparaîtra sur l'appareil

par exemple, il n'y a pas d'ombre dans l'aperçu:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
            <stroke
                android:width="1dp"
                android:color="@color/grey"/>
        </shape>
    </item>
</selector>

mais cela fait:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
            <corners android:radius="1dp" />
            <stroke
                android:width="1dp"
                android:color="@color/grey"/>
        </shape>
    </item>
</selector>

1
L'exact opposé de votre premier point était vrai pour moi dans un article RecyclerView ... C'est incroyable de voir comment je trouve toujours des cas où je dois me battre avec ces API après 5 ans de développement professionnel Android :(
aProperFox

7

L'ajout de la couleur d'arrière-plan m'a aidé.

<CalendarView
    android:layout_width="match_parent"
    android:id="@+id/calendarView"
    android:layout_alignParentTop="true"
    android:layout_alignParentStart="true"
    android:layout_height="wrap_content"
    android:elevation="5dp"

    android:background="@color/windowBackground"

    />

4

Parfois comme background="@color/***"ou background="#ff33**"non, je remplace background_colorpar un dessinable, puis ça marche


4

S'il ne montre toujours pas l'élévation, essayez

    android:hardwareAccelerated="true" 

cela vous aidera certainement.


Cela m'a corrigé. J'avais supposé que VRAI était le paramètre par défaut, mais apparemment pas, du moins dans mon cas.
Matt Robertson

3

Si vous souhaitez avoir un arrière-plan transparent et android:outlineProvider="bounds"ne fonctionne pas pour vous, vous pouvez créer un ViewOutlineProvider personnalisé:

class TransparentOutlineProvider extends ViewOutlineProvider {

    @Override
    public void getOutline(View view, Outline outline) {
        ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
        Drawable background = view.getBackground();
        float outlineAlpha = background == null ? 0f : background.getAlpha()/255f;
        outline.setAlpha(outlineAlpha);
    }
}

Et définissez ce fournisseur sur votre vue transparente:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

Sources: https://code.google.com/p/android/issues/detail?id=78248#c13

[EDIT] La documentation de Drawable.getAlpha () indique qu'elle est spécifique à la façon dont Drawable menace l'alpha. Il est possible qu'il renvoie toujours 255. Dans ce cas, vous pouvez fournir l'alpha manuellement:

class TransparentOutlineProvider extends ViewOutlineProvider {

    private float mAlpha;

    public TransparentOutlineProvider(float alpha) {
        mAlpha = alpha;
    }

    @Override
    public void getOutline(View view, Outline outline) {
        ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
        outline.setAlpha(mAlpha);
    }
}

Si l'arrière-plan de votre vue est un StateListDrawable avec la couleur par défaut # DDFF0000 qui est avec alpha DDx0 / FFx0 == 0,86

transparentView.setOutlineProvider(new TransparentOutlineProvider(0.86f));

2

donner une couleur d'arrière-plan à la mise en page qui a fonctionné pour moi comme:

    android:background="@color/catskill_white"
    android:layout_height="?attr/actionBarSize"
    android:elevation="@dimen/dimen_5dp"

1

J'ai eu de la chance avec la mise clipChildren="false"en page parent.


1

J'ai passé du temps à travailler dessus et j'ai finalement réalisé que lorsque l'arrière-plan est sombre, l'ombre n'est pas visible


1

Ajout à la réponse acceptée, il y a une raison de plus pour laquelle l'élévation peut ne pas fonctionner comme prévu si la fonction de filtre Bluelight sur le téléphone est activée.

J'étais confronté à ce problème lorsque l'élévation est apparue complètement déformée et insupportable dans mon appareil. Mais l'élévation était bonne dans l'aperçu. La désactivation du filtre Bluelight sur le téléphone a résolu le problème.

Donc, même après le réglage

android:outlineProvider="bounds"

L'élévation ne fonctionne pas correctement, alors vous pouvez essayer de bricoler avec les paramètres de couleur du téléphone.


0

Je crois que votre problème vient du fait que vous avez appliqué l'élément d'élévation à une disposition relative qui remplit son parent. Son parent découpe toutes les vues enfant dans son propre canevas de dessin (et c'est la vue qui gère l'ombre de l'enfant). Vous pouvez résoudre ce problème en appliquant une propriété d'élévation au sommet RelativeLayoutde votre vue xml (la balise racine).


0

Dans mon cas, les polices étaient le problème.

1) Sans fontFamily je devais définir android:backgroundune valeur.

<TextView
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@android:color/white"
    android:elevation="3dp"
    android:gravity="center"
    android:text="@string/fr_etalons_your_tickets"
    android:textAllCaps="true"
    android:textColor="@color/blue_4" />

2) avec fontFamilyje devais ajouter le android:outlineProvider="bounds"réglage:

<TextView
    android:fontFamily="@font/gilroy_bold"
    android:layout_width="match_parent"
    android:layout_height="44dp"
    android:background="@android:color/white"
    android:elevation="3dp"
    android:gravity="center"
    android:outlineProvider="bounds"
    android:text="@string/fr_etalons_your_tickets"
    android:textAllCaps="true"
    android:textColor="@color/blue_4" />

0

Dans mon cas, cela a été causé par un composant parent personnalisé définissant le type de couche de rendu sur "Logiciel":

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Supprimer cette ligne a fait l'affaire. Ou bien sûr, vous devez évaluer pourquoi cela existe en premier lieu. Dans mon cas, c'était pour prendre en charge Honeycomb, qui est bien en deçà du SDK minimum actuel pour mon projet.


0

Vérifiez également si vous ne modifiez pas l'alpha dans cette vue. J'étudie le problème lorsque je change l'alpha sur certaines vues, avec élévation. Ils perdent simplement l'élévation lorsque l'alpha est changé et redevient 1f.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.