"Elevação" do Android não mostra sombra

273

Eu tenho um ListView e, com cada item da lista, quero que ele mostre uma sombra abaixo dele. Estou usando o novo recurso de elevação do Android Lollipop para definir um Z na visualização que quero projetar uma sombra e já estou fazendo isso de forma eficaz com o ActionBar (tecnicamente uma barra de ferramentas no Lollipop). Estou usando a elevação do Lollipop, mas por algum motivo ele não está mostrando uma sombra nos itens da lista. Aqui está como o layout de cada item da lista é configurado:

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

No entanto, aqui está como ele mostra o item da lista, sem sombra: insira a descrição da imagem aqui

Eu também tentei o seguinte sem sucesso:

  1. Defina a elevação para os próprios ImageView e TextViews, em vez do layout pai.
  2. Aplicou um plano de fundo ao ImageView.
  3. TranslationZ usado no lugar de Elevation.
AggieDev
fonte
Tentei seu layout (sem visualizações personalizadas) e mostrei a sombra no meu telefone. Você poderia compartilhar um projeto mínimo que reproduz o problema?
rnrneverdies
1
possível duplicata do Android L FAB Button shadow
naveejr 16/12/14
Pergunta relacionada: stackoverflow.com/questions/26572048/…
stefan222

Respostas:

384

Eu brinco com sombras no Lollipop há um tempo e é isso que eu descobri:

  1. Parece que ViewGroupos limites de um pai cortam a sombra de seus filhos por algum motivo; e
  2. as sombras definidas android:elevationsão cortadas pelos Viewlimites do, não os limites estendidos pela margem;
  3. a maneira correta de fazer com que uma exibição filho mostre sombra é definir o preenchimento no pai e definir android:clipToPadding="false"esse pai.

Aqui está minha sugestão para você, com base no que eu sei:

  1. Defina seu nível superior RelativeLayoutpara que o preenchimento seja igual às margens definidas no layout relativo que você deseja mostrar sombra;
  2. definido android:clipToPadding="false"no mesmo RelativeLayout;
  3. Remova a margem da RelativeLayoutque também possui elevação definida;
  4. [EDIT] também pode ser necessário definir uma cor de fundo não transparente no layout filho que precisa de elevação.

No final do dia, seu layout relativo de nível superior deve ficar assim:

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

O layout relativo interno deve ficar assim:

<RelativeLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:background="[some non-transparent color]"
    android:elevation="30dp"
    >
Justin Pollard
fonte
8
Obrigado por isso! Também achei que android: clipChildren = "false" é útil quando aplicado ao layout relativo dos pais.
blaffie
1
Fico feliz em ajudar @blaffie!
23715 Justin
214
É tão irritante que o Google produz um código tão ruim. Teremos que prestar contas desses bugs de estrutura por anos.
miguel
8
O Google apenas diz (infelizmente): "As sombras são desenhadas pelo pai da vista elevada e, portanto, sujeitas ao recorte de vista padrão, recortado pelo pai por padrão. ".
John
5
No meu caso, era a cor transparente. Ok, as coisas transparentes não lançar sombras ... haha
Ferran Maylinch
286

Se você tem uma visão sem fundo, esta linha o ajudará

android:outlineProvider="bounds"

Por padrão, a sombra é determinada pelo plano de fundo da visualização; portanto, se não houver plano de fundo, também não haverá sombra.

Dmitry Ryadnenko
fonte
11
Que coisa estranha, o Preview mostrou elevação, mas o dispositivo real não. Obrigado, este corrigiu o problema.
Ioane Sharvadze
Obras de nível API 21 e superior
Pantelis Ieronimakis
10
Isso meio que funcionou para mim, mas deu uma borda diagonal nas laterais quando aplicada a uma visualização de texto. Definir o plano de fundo para uma cor (igual à cor de plano de fundo dos pais) funcionou melhor.
Gober
4
Isso também se aplica se o seu plano de fundo for personalizado e não tiver <solid>.
David Lord
Isso pode ser usado ao contrário. Quando você deseja um plano de fundo não transparente com elevação e não deseja sombra. Basta configurá-lo para none. Obrigado!
Odys
101

Aparentemente, você não pode simplesmente definir uma elevação em uma vista e fazer com que ela apareça. Você também precisa especificar um plano de fundo.

As seguintes linhas adicionadas ao meu LinearLayout finalmente mostraram uma sombra:

android:background="@android:color/white"
android:elevation="10dp"
John Slavick
fonte
Foi inesperado. Eu configurei o ImageView com src e estava procurando solução. Obrigado.
Andrew Grow
47

outra coisa que você deve estar ciente: as sombras não serão exibidas se você tiver esta linha no manifesto:

android: hardwareAccelerated = "false"

Eu tentei todas as coisas sugeridas, mas só funcionou para mim quando removi a linha, a razão pela qual eu tinha a linha era porque meu aplicativo trabalha com várias imagens de bitmap e elas estavam causando a falha do aplicativo.

nada
fonte
1
Isso não resolve o problema, se você precisar que o sinalizador esteja presente.
Clive Jefferies
obrigado!! Passei um dia tentando elevar o AppBar e descobriu o problema quando eu verifiquei o manifesto para esta bandeira actividade
ir2pid
1
Tentei todas as soluções possíveis, mas nada funcionou para mim. Essas soluções funcionaram. Obrigado. Também precisa android:clipToPadding="false"com esta solução.
Chirag Savsani
29

Se você tem uma visão sem fundo, esta linha o ajudará

android:outlineProvider="bounds"

Se você tem uma visão com plano de fundo, esta linha o ajudará

android:outlineProvider="paddedBounds"
Deepak sharma
fonte
6
Esta solução é a única que funciona para mim. Obrigado
Oleh Liskovych
4
Isso funciona, a menos que você tenha um raio no plano de fundo das visualizações, nesse caso a sombra será mostrada como retangular, mas paddedBounds funciona para uma visualização com plano de fundo.
Trevor Hart
android:outlineProvider="paddedBounds"essa linha funcionou para mim. Defino o Seletor Drawable.
Chirag Savsani
1
Quando usei isso, a sombra é desenhada completamente dentro da vista e não fora, o que não é o que eu quero.
androidguy
12

Ugh, apenas passei uma hora tentando descobrir isso. No meu caso, eu tinha um conjunto de plano de fundo, no entanto, estava definido como uma cor. Isso não é suficiente, você precisa ter o plano de fundo da visualização definido como um drawable.

Por exemplo, isso não terá sombra:

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

mas isso vai

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

EDIT: Também descobriram que, se você usar um seletor como plano de fundo, se não tiver o canto definido, a sombra não aparecerá na janela Visualizar, mas aparecerá no dispositivo

Por exemplo, isso não tem sombra na visualização:

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

mas isso faz:

<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>
odiggity
fonte
1
O oposto exato do seu primeiro ponto foi verdadeiro para mim em um item do RecyclerView ... É incrível como ainda encontro casos em que tenho que lutar com essas APIs após 5 anos de desenvolvimento profissional do Android :(
aProperFox
7

Adicionar cor de fundo me ajudou.

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

    />
Tim Glenn
fonte
4

Às vezes gosto background="@color/***"ou background="#ff33**"não funciona, substituo background_colorpor drawable, depois funciona

ray liu
fonte
4

Se ainda não mostrar elevação, tente

    android:hardwareAccelerated="true" 

isso definitivamente irá ajudá-lo.

Rohit Lalwani
fonte
Isso consertou para mim. Eu assumi que TRUE era a configuração padrão, mas aparentemente não, pelo menos no meu caso.
Matt Robertson
3

Se você deseja ter um plano de fundo transparente e android:outlineProvider="bounds"não funcionar, crie um 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);
    }
}

E defina esse provedor para sua visão transparente:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

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

[EDIT] A documentação de Drawable.getAlpha () diz que é específico de como o Drawable ameaça o alfa. É possível que ele sempre retorne 255. Nesse caso, você pode fornecer o 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 o plano de fundo da visualização for um StateListDrawable com a cor padrão # DDFF0000, com alfa DDx0 / FFx0 == 0,86

transparentView.setOutlineProvider(new TransparentOutlineProvider(0.86f));
wirdil
fonte
2

dê alguma cor de fundo ao layout que funcionou para mim como:

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

Tive alguma sorte com a configuração clipChildren="false"no layout dos pais.

Kavi
fonte
1

Passei algum tempo trabalhando nisso e finalmente percebi que quando o fundo está escuro, a sombra não é visível

Efi G
fonte
1

Além da resposta aceita, há mais um motivo pelo qual a elevação pode não funcionar conforme o esperado, se o recurso de filtro Bluelight no telefone estiver ligado.

Eu estava enfrentando esse problema quando a elevação parecia completamente distorcida e insuportável no meu dispositivo. Mas a elevação foi boa na visualização. Desligar o filtro Bluelight no telefone resolveu o problema.

Então, mesmo depois de definir

android:outlineProvider="bounds"

A elevação não está funcionando corretamente, então você pode tentar mexer nas configurações de cores do telefone.

Hemang Kumar
fonte
0

Acredito que seu problema decorra do fato de você ter aplicado o elemento de elevação a um layout relativo que preenche seu pai. Seu pai corta todas as vistas filho dentro de sua própria tela de desenho (e é a vista que lida com a sombra da criança). Você pode corrigir isso aplicando uma propriedade de elevação na parte superior do RelativeLayoutxml da visualização (a marca raiz).

FluffyC4n't
fonte
0

No meu caso, as fontes eram o problema.

1) Sem fontFamilyeu precisava definir android:backgroundcom algum 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) com fontFamilyeu tive que adicionar android:outlineProvider="bounds"configuração:

<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" />
soshial
fonte
0

No meu caso, isso foi causado por um componente pai personalizado configurando o tipo de camada de renderização para "Software":

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Remover esta linha de fez o truque. Ou, é claro, você precisa avaliar por que isso ocorre em primeiro lugar. No meu caso, era oferecer suporte ao Honeycomb, que está bem atrás do SDK mínimo atual do meu projeto.

ErrricP
fonte
0

Verifique também se Você não altera o alfa nessa exibição. Estou investigando o problema quando altero o alfa em algumas visualizações, com elevação. Eles simplesmente perdem a elevação quando o alfa é alterado e alterado novamente para 1f.

Milan Jurkulak
fonte