Android "elevazione" non mostra un'ombra


273

Ho un ListView e con ogni elemento dell'elenco voglio che mostri un'ombra sotto di esso. Sto usando la nuova funzione di elevazione di Android Lollipop per impostare una Z sulla vista che voglio proiettare un'ombra e lo sto già facendo efficacemente con ActionBar (tecnicamente una barra degli strumenti in Lollipop). Sto usando l'elevazione di Lollipop, ma per qualche motivo non mostra un'ombra sotto gli elementi dell'elenco. Ecco come è impostato il layout di ciascun elemento dell'elenco:

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

Tuttavia, ecco come mostra l'elemento dell'elenco, senza ombre: inserisci qui la descrizione dell'immagine

Ho anche provato quanto segue inutilmente:

  1. Impostare l'elevazione su ImageView e TextViews stessi anziché sul layout principale.
  2. Applicato uno sfondo a ImageView.
  3. Usato TranslationZ al posto di Elevation.

Ho provato il tuo layout (senza visualizzazioni personalizzate) e ho mostrato l'ombra nel mio telefono, potresti condividere un progetto minimo che riproduca il problema?
rnrneverdies,

1
possibile duplicato di Android L FAB Button shadow
naveejr il

Risposte:


384

Ho giocato un po 'con le ombre su Lollipop e questo è quello che ho trovato:

  1. Sembra che ViewGroupi limiti di un genitore abbiano tagliato l'ombra dei suoi figli per qualche motivo; e
  2. le ombre impostate con android:elevationsono tagliate dai Viewlimiti, non dai limiti estesi attraverso il margine;
  3. il modo giusto per ottenere una vista figlio per mostrare l'ombra è impostare il riempimento sul genitore e android:clipToPadding="false"su quel genitore.

Ecco il mio suggerimento per te in base a ciò che so:

  1. Imposta il tuo livello più alto RelativeLayoutin modo che il padding sia uguale ai margini che hai impostato sul layout relativo che vuoi mostrare all'ombra;
  2. impostato android:clipToPadding="false"sullo stesso RelativeLayout;
  3. Rimuovere il margine dal RelativeLayoutche ha anche impostato elevazione;
  4. [MODIFICA] potrebbe anche essere necessario impostare un colore di sfondo non trasparente sul layout secondario che necessita di elevazione.

Alla fine della giornata, il layout relativo di livello superiore dovrebbe assomigliare a questo:

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

Il layout relativo interno dovrebbe assomigliare a questo:

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

8
Grazie per questo! Ho anche trovato Android: clipChildren = "false" per essere utile quando applicato al layout relativo dei genitori.
Blaffie,

1
Sono contento di aiutare @blaffie!
Justin Pollard,

214
È così fastidioso che Google produca un codice così scadente. Dovremo tenere conto di questi bug del framework per anni.
miguel,

8
Google dice solo (purtroppo): "Le ombre sono disegnate dal genitore della vista elevata, e quindi soggette al ritaglio della vista standard, ritagliate dal genitore di default. ".
Giovanni,

5
Nel mio caso era il colore trasparente. Ok, le cose trasparenti non proiettano ombre ... haha
Ferran Maylinch,

286

Se hai una vista senza sfondo questa riga ti aiuterà

android:outlineProvider="bounds"

Per impostazione predefinita, l'ombra è determinata dallo sfondo della vista, quindi se non c'è sfondo, non ci sarà nemmeno ombra.


11
Che cosa strana, l'anteprima ha mostrato l'elevazione ma il dispositivo reale no. Grazie, questo ha risolto il problema.
Ioane Sharvadze,

Funziona con API di livello 21 e superiore
Pantelis Ieronimakis,

10
Questo tipo di lavoro ha funzionato per me, ma ha dato un bordo diagonale ai lati quando applicato a una visualizzazione di testo. L'impostazione dello sfondo su un colore (uguale al colore di sfondo dei genitori) ha funzionato meglio.
Gober,

4
Questo vale anche se lo sfondo è personalizzato e non ha <solid>.
David Lord,

Questo può essere usato al contrario. Quando si desidera uno sfondo non trasparente con elevazione e non si desidera l'ombra. Basta impostarlo su none. Grazie!
Odys,

101

Apparentemente, non puoi semplicemente impostare un'altitudine su una vista e farla apparire. È inoltre necessario specificare uno sfondo.

Le seguenti righe aggiunte al mio LinearLayout hanno finalmente mostrato un'ombra:

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

È stato inaspettato. Ho impostato ImageView con SRC e cercavo una soluzione. Grazie.
Andrew Grow,

47

un'altra cosa di cui dovresti essere a conoscenza, le ombre non mostreranno se hai questa linea nel manifest:

Android: hardwareAccelerated = "false"

Ho provato tutte le cose suggerite ma ha funzionato solo per me quando ho rimosso la linea, il motivo per cui avevo la linea era perché la mia app funziona con un numero di immagini bitmap e stavano causando il crash dell'app.


1
Questo non risolve il problema, se è necessario che la bandiera sia presente.
Clive Jefferies

grazie!! Ho trascorso una giornata cercando di elevare l'AppBar e ho riscontrato il problema quando ho controllato il manifest per questa bandiera di attività
ir2pid

1
Ho provato tutte le possibili soluzioni, ma nessuna di lavoro per me. Questa soluzione ha funzionato. Grazie. Necessario anche android:clipToPadding="false"con questa soluzione.
Chirag Savsani,

29

Se hai una vista senza sfondo questa riga ti aiuterà

android:outlineProvider="bounds"

Se hai una vista sullo sfondo questa linea ti aiuterà

android:outlineProvider="paddedBounds"

6
Questa soluzione è l'unica che funziona per me. Grazie
Oleh Liskovych,

4
Funziona a meno che tu non abbia un raggio sullo sfondo delle viste, nel qual caso l'ombra mostrerà come rettangolare, ma paddedBounds funziona per una vista con uno sfondo.
Trevor Hart

android:outlineProvider="paddedBounds"questa linea ha funzionato per me. Ho impostato Selable Drawable.
Chirag Savsani,

1
Quando l'ho usato, l'ombra viene disegnata completamente all'interno della vista anziché all'esterno, il che non è quello che voglio.
androidguy il


12

Ugh, ho passato solo un'ora a cercare di capirlo. Nel mio caso avevo uno sfondo impostato, tuttavia era impostato su un colore. Questo non è abbastanza, devi avere lo sfondo della vista impostato su un disegno.

ad es. questo non avrà un'ombra:

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

ma questo lo farà

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

EDIT: hanno anche scoperto che se si utilizza un selettore come sfondo, se non si imposta l'angolo, l'ombra non verrà visualizzata nella finestra Anteprima ma verrà visualizzata sul dispositivo

es. Questo non ha un'ombra in anteprima:

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

ma questo fa:

<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'esatto contrario del tuo primo punto era vero per me in un oggetto RecyclerView ... È incredibile come trovo ancora casi in cui devo combattere con queste API dopo 5 anni di sviluppo professionale su Android :(
aProperFox

7

L'aggiunta del colore di sfondo mi ha aiutato.

<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

A volte piace background="@color/***"o background="#ff33**"non funziona, lo sostituisco background_colorcon il disegno, quindi funziona


4

Se non mostra ancora l'elevazione, provare

    android:hardwareAccelerated="true" 

questo ti aiuterà sicuramente.


Questo mi ha risolto. Avevo supposto che TRUE fosse l'impostazione predefinita, ma apparentemente no, almeno nel mio caso.
Matt Robertson,

3

Se vuoi avere uno sfondo trasparente e android:outlineProvider="bounds"non funziona per te, puoi creare ViewOutlineProvider personalizzato:

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

E imposta questo provider sulla tua vista trasparente:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

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

[EDIT] La documentazione di Drawable.getAlpha () afferma che è specifica di come il Drawable minaccia l'alfa. È possibile che restituisca sempre 255. In questo caso puoi fornire l'alfa manualmente:

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

Se lo sfondo della vista è un StateListDrawable con colore predefinito # DDFF0000 ovvero con alpha DDx0 / FFx0 == 0,86

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

2

dai un po 'di colore di sfondo al layout lavorato per me come:

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

1

Ho avuto un po 'di fortuna con l'impostazione clipChildren="false"sul layout genitore.


1

Ho trascorso un po 'di tempo a lavorarci su e finalmente ho capito che quando lo sfondo è scuro, l'ombra non è visibile


1

Aggiungendo alla risposta accettata, c'è un motivo in più a causa del quale l'elevazione potrebbe non funzionare come previsto se la funzione di filtro Bluelight sul telefono è attiva.

Stavo affrontando questo problema quando l'elevazione sembrava completamente distorta e insopportabile nel mio dispositivo. Ma l'altitudine era soddisfacente nell'anteprima. La disattivazione del filtro Bluelight sul telefono ha risolto il problema.

Quindi, anche dopo l'impostazione

android:outlineProvider="bounds"

L'elevazione non funziona correttamente, quindi puoi provare ad armeggiare con le impostazioni del colore del telefono.


0

Credo che il tuo problema derivi dal fatto che hai applicato l'elemento di elevazione a un layout relativo che riempie il suo genitore. Il suo genitore ritaglia tutte le viste figlio all'interno della propria area di disegno (ed è la vista che gestisce l'ombra del bambino). È possibile risolvere questo problema applicando una proprietà di elevazione al massimo RelativeLayoutnella vista xml (il tag radice).


0

Nel mio caso i font erano il problema.

1) Senza fontFamilyho bisogno di impostare un android:backgroundcerto valore.

<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) con fontFamilyho dovuto aggiungere l' android:outlineProvider="bounds"impostazione:

<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

Nel mio caso, ciò è stato causato da un componente genitore personalizzato che imposta il tipo di livello di rendering su "Software":

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Rimuovere questa linea ha fatto il trucco. O ovviamente devi valutare perché questo è lì, in primo luogo. Nel mio caso è stato per supportare Honeycomb, che è ben dietro l'attuale SDK minimo per il mio progetto.


0

Controlla anche se non cambi l'alfa in quella vista. Sto indagando sul problema quando cambio alpha in alcune viste, con elevazione. Perdono semplicemente elevazione quando l'alfa viene cambiata e ripristinata a 1f.

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.