304

I have a ListView, and with each list item I want it to show a shadow beneath it. I am using Android Lollipop's new elevation feature to set a Z on the View that I want to cast a shadow, and am already doing this effectively with the ActionBar (technically a Toolbar in Lollipop). I am using Lollipop's elevation, but for some reason it isn't showing a shadow under the list items. Here is how each list item's layout is set up:

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

However, here is how it shows the list item, without a shadow: enter image description here

I have also tried the following to no avail:

  1. Set the elevation to the ImageView and TextViews themselves instead of the parent layout.
  2. Applied a background to the ImageView.
  3. Used TranslationZ in place of Elevation.
AggieDev
  • 4,604
  • 9
  • 24
  • 46
  • I tried your layout (without customviews) and shown the shadow in my phone, could you share a minimal project which reproduce the issue? – rnrneverdies Dec 15 '14 at 13:55
  • 1
    possible duplicate of [Android L FAB Button shadow](http://stackoverflow.com/questions/24480425/android-l-fab-button-shadow) – naveejr Dec 16 '14 at 07:08
  • Related question: http://stackoverflow.com/questions/26572048/elevation-on-android-lollipop-not-working – stefan222 May 19 '15 at 06:55

21 Answers21

417

I've been playing around with shadows on Lollipop for a bit and this is what I've found:

  1. It appears that a parent ViewGroup's bounds cutoff the shadow of its children for some reason; and
  2. shadows set with android:elevation are cutoff by the View's bounds, not the bounds extended through the margin;
  3. the right way to get a child view to show shadow is to set padding on the parent and set android:clipToPadding="false" on that parent.

Here's my suggestion to you based on what I know:

  1. Set your top-level RelativeLayout to have padding equal to the margins you've set on the relative layout that you want to show shadow;
  2. set android:clipToPadding="false" on the same RelativeLayout;
  3. Remove the margin from the RelativeLayout that also has elevation set;
  4. [EDIT] you may also need to set a non-transparent background color on the child layout that needs elevation.

At the end of the day, your top-level relative layout should look like this:

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

The interior relative layout should look like this:

<RelativeLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:background="[some non-transparent color]"
    android:elevation="30dp"
    >
syntagma
  • 20,485
  • 13
  • 66
  • 121
Justin Pollard
  • 6,291
  • 1
  • 16
  • 20
  • 9
    Thanks for this! I also found android:clipChildren="false" to be useful when applied to the parent relative layout. – blaffie Mar 11 '15 at 19:16
  • 1
    Glad to help @blaffie! – Justin Pollard Mar 11 '15 at 19:22
  • 236
    It's so annoying that Google produces such shoddy code. We'll have to account for these framework bugs for years. – miguel Jun 19 '15 at 22:34
  • Great answer, you gave us good insight on how it all works more than simply giving away the solution. – Eduardo Lino Aug 13 '15 at 18:24
  • 12
    Google only says (alas) : "_Shadows are drawn by the parent of the elevated view, and thus subject to standard view clipping, clipped by the parent by default._". – John Sep 27 '15 at 15:46
  • 1
    If your view is using a color with an alpha channel, there's a bug, so you would need to omit the alpha channel. (For example, change #7d0073ff to #0073ff.) See http://stackoverflow.com/a/26581346/2423194 – Rock Lee Jan 08 '16 at 00:59
  • 1
    I don't know if it's a bug, but that's true, which is why I wrote `android:background="[some non-transparent color]"` ;-) – Justin Pollard Jan 08 '16 at 03:42
  • 5
    In my case it was the transparent color. Ok, transparent things don't cast shadows... haha – Ferran Maylinch Apr 05 '16 at 12:25
  • If you are wrapping buttons in a Viewgroup, you always need to use a padding, otherwise it's not gonna work, even adding clipChildren and clipPadding, right? @joe-birch – cesards Oct 03 '16 at 16:16
  • @cesards I believe you can also add margin to the element with a shadow instead of padding if you like. – Justin Pollard Oct 04 '16 at 18:33
  • Yup. It's a pain anyway xDDD – cesards Oct 05 '16 at 17:20
  • This android:clipToPadding="false" is a life-saver for material Buttons, as well. So, always put a Button wrapped in a RelativeLayout with clip set to false, and shadows work without any issues. – miroslavign Oct 10 '16 at 07:52
  • android:clipToPadding="false" adding to layout worked for me – Shiba Das Dec 24 '20 at 14:21
319

If you have a view with no background this line will help you

android:outlineProvider="bounds"

By default shadow is determined by view's background, so if there is no background, there will be no shadow also.

Dmitry Ryadnenko
  • 20,952
  • 4
  • 38
  • 52
  • 12
    What a strange thing, Preview showed elevation but real device didn't. Thanks, this one fixed the issue. – Ioane Sharvadze Feb 29 '16 at 10:47
  • 1
    Works for API level 21 and higher – Pantelis Ieronimakis Apr 12 '16 at 22:44
  • 10
    This sort of worked for me, but gave a diagonal border on the sides when applied to a textview. Setting the background to a color (same as parents background color) worked better. – Gober Jun 21 '16 at 11:21
  • 5
    This also applies if your background is custom and has no ``. – David Lord Dec 25 '16 at 03:34
  • This can be used in reverse. When you want a non-transparent background with elevation and dont want shadow. Simply set it to `none`. Thanks! – Odys Jan 26 '18 at 11:50
  • I tried this after I had gotten it working with the accepted answer because it seemed more simple and less error-prone. However, this didn't work for me because my background border has rounded corners. – beyondtheteal Jul 03 '19 at 15:36
  • For most of my views, I have rounded corners and this resulted in sharp, non-rounded shadow corners. I found this solution (https://stackoverflow.com/a/60424218) helpful for elevated views with round corners. – Android Oct 08 '20 at 22:36
110

Apparently, you cannot just set an elevation on a View and have it appear. You also need to specify a background.

The following lines added to my LinearLayout finally showed a shadow:

android:background="@android:color/white"
android:elevation="10dp"
John Slavick
  • 9,145
  • 4
  • 25
  • 23
52

one other thing that you should be aware of, shadows will not show if you have this line in the manifest:

android:hardwareAccelerated="false"

I tried all of the suggested stuff but it only worked for me when i removed the line, the reason i had the line was because my app works with a number of bitmap images and they were causing the app to crash.

nada
  • 1,319
  • 9
  • 17
42

If you have a view with no background this line will help you

android:outlineProvider="bounds"

If you have a view with background this line will help you

android:outlineProvider="paddedBounds"
Deepak sharma
  • 607
  • 6
  • 7
20

If you are adding elevation to a button element, you need to add the following line:

android:stateListAnimator="@null"

See Android 5.0 android:elevation Works for View, but not Button?

Patrick Trentin
  • 6,721
  • 3
  • 20
  • 38
user8102108
  • 209
  • 2
  • 2
13

Ugh, just spent an hour trying to figure this out. In my case I had a background set, however it was set to a color. This is not enough, you need to have the background of the view set to a drawable.

e.g. This won't have a shadow:

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

but this will

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

EDIT: Have also discovered that if you use a selector as a background, if you don't have the corner set then the shadow won't show up in the Preview window but it will show up on the device

e.g. This doesn't have a shadow in preview:

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

but this does:

<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
  • 4,059
  • 6
  • 30
  • 40
  • 1
    The exact opposite of your first point was true for me in a RecyclerView item... It's amazing how I still find cases where I have to battle with these APIs after 5 years of professional Android development :( – aProperFox Jan 03 '19 at 21:19
8

Adding background color helped me.

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

    />
Paul Roub
  • 35,100
  • 27
  • 72
  • 83
Tim Glenn
  • 206
  • 2
  • 6
4

Adding to the accepted answer, there is one more reason due to which elevation may not work as expected if the Bluelight filter feature on the phone is ON.

I was facing this issue when the elevation appeared completely distorted and unbearable in my device. But the elevation was fine in the preview. Turning off the Bluelight filter on phone resolved the issue.

So even after setting

android:outlineProvider="bounds"

The elevation is not working properly, then you can try to tinker with phone's color settings.

Hemang Kumar
  • 41
  • 1
  • 4
4

Sometimes like background="@color/***" or background="#ff33**" not work, I replace background_color with drawable, then it works

Paul Chu
  • 1,209
  • 3
  • 16
  • 23
ray liu
  • 57
  • 2
4

If it still not showing elevation try

    android:hardwareAccelerated="true" 

this will definitely help you.

Rohit Lalwani
  • 379
  • 4
  • 12
3

If you want to have transparent background and android:outlineProvider="bounds" doesn't work for you, you can create custom ViewOutlineProvider:

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

And set this provider to your transparent view:

transparentView.setOutlineProvider(new TransparentOutlineProvider());

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

[EDIT] Documentation of Drawable.getAlpha() says that it is specific to how the Drawable threats the alpha. It is possible that it will always return 255. In this case you can provide the alpha manually:

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

If your view background is a StateListDrawable with default color #DDFF0000 that is with alpha DDx0/FFx0 == 0.86

transparentView.setOutlineProvider(new TransparentOutlineProvider(0.86f));
wirdil
  • 256
  • 3
  • 7
3

give some background color to layout worked for me like:

    android:background="@color/catskill_white"
    android:layout_height="?attr/actionBarSize"
    android:elevation="@dimen/dimen_5dp"
sudhakara k s
  • 197
  • 1
  • 7
1

I had some luck with setting clipChildren="false" on the parent layout.

Kavi
  • 3,810
  • 2
  • 24
  • 23
1

I spent some time working on it and finally realized that when the background is dark, shadow is not visible

Efi G
  • 667
  • 5
  • 12
1

Also check if You don't change alpha on that view. I am investigating issue when i change alpha on some views, with elevation. They simply loose elevation when alpha is changed and changed back to 1f.

Milan Jurkulak
  • 303
  • 1
  • 5
0

I believe your issue stems from the fact that you have applied the elevation element to a relative layout that fills its parent. Its parent clips all child views within its own drawing canvas (and is the view that handles the child's shadow). You can fix this by applying an elevation property to the topmost RelativeLayout in your view xml (the root tag).

intcreator
  • 3,161
  • 4
  • 18
  • 36
0

In my case fonts were the problem.

1) Without fontFamily I needed to set android:background to some value.

<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) with fontFamily I had to add android:outlineProvider="bounds" setting:

<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
  • 3,252
  • 4
  • 27
  • 36
0

In my case, this was caused by a custom parent component setting the rendering layer type to "Software":

setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Removing this line of did the trick. Or course you need to evaluate why this is there in the first place. In my case it was to support Honeycomb, which is well behind the current minimum SDK for my project.

0

Setting android:clipToPadding="false" in the top relative layout has solved the problem.

rajkabbur
  • 151
  • 3
-1

set background color to the layout or view