La "elevación" de Android no muestra una sombra


273

Tengo un ListView, y con cada elemento de la lista quiero que muestre una sombra debajo de él. Estoy usando la nueva función de elevación de Android Lollipop para establecer una Z en la vista en la que quiero proyectar una sombra, y ya lo estoy haciendo de manera efectiva con la barra de acciones (técnicamente una barra de herramientas en Lollipop). Estoy usando la elevación de Lollipop, pero por alguna razón no muestra una sombra debajo de los elementos de la lista. Así es como se configura el diseño de cada elemento de la lista:

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

Sin embargo, así es como muestra el elemento de la lista, sin sombra: ingrese la descripción de la imagen aquí

También he intentado lo siguiente en vano:

  1. Establezca la elevación en ImageView y TextViews en lugar del diseño primario.
  2. Aplica un fondo a ImageView.
  3. TranslationZ usado en lugar de elevación.

Probé su diseño (sin vistas personalizadas) y mostré la sombra en mi teléfono, ¿podría compartir un proyecto mínimo que reproduzca el problema?
rnrneverdies

1
posible duplicado de Android L FAB Button shadow
naveejr

Respuestas:


384

He estado jugando con sombras en Lollipop durante un tiempo y esto es lo que he encontrado:

  1. Parece que ViewGrouplos límites de un padre cortan la sombra de sus hijos por alguna razón; y
  2. las sombras establecidas con android:elevationson cortadas por los Viewlímites de s, no los límites extendidos a través del margen;
  3. la forma correcta de obtener una vista secundaria para mostrar sombra es establecer el relleno en el elemento primario y establecerlo android:clipToPadding="false"en ese elemento primario.

Aquí está mi sugerencia basada en lo que sé:

  1. Configure su nivel superior RelativeLayoutpara que tenga un relleno igual a los márgenes que ha establecido en el diseño relativo que desea mostrar sombra;
  2. puesto android:clipToPadding="false"en el mismo RelativeLayout;
  3. Elimine el margen del RelativeLayoutque también tiene un conjunto de elevación;
  4. [EDITAR] también puede necesitar establecer un color de fondo no transparente en el diseño secundario que necesita elevación.

Al final del día, su diseño relativo de nivel superior debería verse así:

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

El diseño relativo interior debería verse así:

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

8
¡Gracias por esto! También encontré que android: clipChildren = "false" es útil cuando se aplica al diseño relativo principal.
blaffie

1
Me alegro de ayudar a @blaffie!
Justin Pollard

214
Es tan molesto que Google produce un código de mala calidad. Tendremos que dar cuenta de estos errores del marco durante años.
miguel

8
Google solo dice (por desgracia): "Las sombras son dibujadas por el padre de la vista elevada y, por lo tanto, sujetas al recorte de vista estándar, recortado por el padre de forma predeterminada ".
John

55
En mi caso fue el color transparente. Ok, las cosas transparentes no proyectan sombras ... jaja
Ferran Maylinch

286

Si tiene una vista sin fondo, esta línea lo ayudará

android:outlineProvider="bounds"

De forma predeterminada, la sombra está determinada por el fondo de la vista, por lo que si no hay fondo, tampoco habrá sombra.


11
Qué cosa más extraña, Vista previa mostró elevación, pero el dispositivo real no. Gracias, este solucionó el problema.
Ioane Sharvadze

Funciona para API nivel 21 y superior
Pantelis Ieronimakis

10
Esto me funcionó, pero dio un borde diagonal a los lados cuando se aplicó a una vista de texto. Establecer el fondo en un color (igual que el color de fondo de los padres) funcionó mejor.
Gober

44
Esto también se aplica si su fondo es personalizado y no tiene <solid>.
David Lord

Esto se puede usar a la inversa. Cuando desee un fondo no transparente con elevación y no desee sombras. Simplemente configúrelo en none. ¡Gracias!
Odys

101

Aparentemente, no puede simplemente establecer una elevación en una Vista y hacer que aparezca. También debe especificar un fondo.

Las siguientes líneas agregadas a mi LinearLayout finalmente mostraron una sombra:

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

Fue inesperado He configurado ImageView con src y estaba buscando una solución. Gracias.
Andrew Grow

47

Otra cosa que debe tener en cuenta, las sombras no se mostrarán si tiene esta línea en el manifiesto:

android: hardwareAccelerated = "false"

Intenté todas las cosas sugeridas, pero solo funcionó para mí cuando eliminé la línea, la razón por la que tenía la línea era porque mi aplicación funciona con varias imágenes de mapa de bits y estaban causando que la aplicación se bloqueara.


1
Esto no resuelve el problema, si necesita que esa bandera esté presente.
Clive Jefferies

¡¡gracias!! Pasé un día tratando de elevar la barra de aplicaciones y encontré el problema cuando revisé el manifiesto de esta bandera de actividad
ir2pid

1
Intenté todas las soluciones posibles, pero ninguna me funcionó. Estas soluciones funcionaron. Gracias. También necesita android:clipToPadding="false"con esta solución.
Chirag Savsani

29

Si tiene una vista sin fondo, esta línea lo ayudará

android:outlineProvider="bounds"

Si tiene una vista con fondo, esta línea lo ayudará

android:outlineProvider="paddedBounds"

66
Esta solución es la única que me funciona. Gracias
Oleh Liskovych

44
Esto funciona a menos que tenga un radio en el fondo de sus vistas, en cuyo caso la sombra se mostrará como rectangular, pero paddedBounds funciona para una vista con un fondo.
Trevor Hart el

android:outlineProvider="paddedBounds"Esta línea me funcionó. Configuré Selector Drawable.
Chirag Savsani

1
Cuando usé esto, la sombra se dibuja completamente dentro de la vista en lugar de afuera, que no es lo que quiero.
androidguy


12

Ugh, acabo de pasar una hora tratando de resolver esto. En mi caso tenía un conjunto de fondo, sin embargo, estaba configurado en un color. Esto no es suficiente, debe tener el fondo de la vista establecido en dibujable.

Por ejemplo, esto no tendrá sombra:

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

pero esto lo hará

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

EDITAR: también descubrí que si usa un selector como fondo, si no tiene la esquina configurada, la sombra no se mostrará en la ventana Vista previa, pero se mostrará en el dispositivo

Por ejemplo, esto no tiene una sombra en la vista previa:

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

pero esto hace:

<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
Todo lo contrario de su primer punto fue cierto para mí en un artículo RecyclerView ... Es sorprendente cómo todavía encuentro casos en los que tengo que luchar con estas API después de 5 años de desarrollo profesional de Android :(
aProperFox

7

Agregar color de fondo me ayudó.

<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 veces me gusta background="@color/***"o background="#ff33**"no funciona, lo reemplazo background_colorcon dibujable, luego funciona


4

Si aún no muestra elevación, intente

    android:hardwareAccelerated="true" 

esto definitivamente te ayudará.


Esto me lo arregló. Asumí que VERDADERO era la configuración predeterminada, pero aparentemente no, al menos en mi caso.
Matt Robertson

3

Si desea tener un fondo transparente y android:outlineProvider="bounds"no funciona para usted, puede crear ViewOutlineProvider personalizado:

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

Y configure este proveedor en su vista transparente:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

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

[EDITAR] La documentación de Drawable.getAlpha () dice que es específica de cómo el Drawable amenaza al alfa. Es posible que siempre devuelva 255. En este caso, puede proporcionar el 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);
    }
}

Si su fondo de vista es un StateListDrawable con el color predeterminado # DDFF0000 que es con alfa DDx0 / FFx0 == 0.86

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

2

dar un poco de color de fondo al diseño me funcionó como:

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

1

Tuve un poco de suerte con la configuración clipChildren="false"del diseño principal.


1

Pasé algún tiempo trabajando en ello y finalmente me di cuenta de que cuando el fondo es oscuro, la sombra no es visible


1

Además de la respuesta aceptada, hay una razón más por la cual la elevación puede no funcionar como se espera si la función de filtro Bluelight en el teléfono está activada.

Estaba enfrentando este problema cuando la elevación parecía completamente distorsionada e insoportable en mi dispositivo. Pero la elevación estaba bien en la vista previa. Desactivar el filtro Bluelight en el teléfono resolvió el problema.

Entonces, incluso después de configurar

android:outlineProvider="bounds"

La elevación no funciona correctamente, entonces puede intentar modificar la configuración de color del teléfono.


0

Creo que su problema se debe al hecho de que ha aplicado el elemento de elevación a un diseño relativo que llena su elemento primario. Su padre recorta todas las vistas secundarias dentro de su propio lienzo de dibujo (y es la vista que maneja la sombra del niño). Puede solucionar esto aplicando una propiedad de elevación en la parte superior RelativeLayoutde su vista xml (la etiqueta raíz).


0

En mi caso, las fuentes eran el problema.

1) Sin fontFamilyque necesitaba establecer android:backgroundalgún valor.

<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 fontFamilytuve que agregar android:outlineProvider="bounds"configuración:

<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

En mi caso, esto fue causado por un componente padre personalizado que configura el tipo de capa de representación en "Software":

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Eliminar esta línea hizo el truco. O, por supuesto, debe evaluar por qué esto está allí en primer lugar. En mi caso, fue para admitir Honeycomb, que está muy por detrás del SDK mínimo actual para mi proyecto.


0

Compruebe también si no cambia alfa en esa vista. Estoy investigando un problema cuando cambio alfa en algunas vistas, con elevación. Simplemente pierden elevación cuando se cambia alfa y se vuelve a cambiar a 1f.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.