Android "elevation" not showing a shadow
Asked Answered
C

23

336

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.
Cleodel answered 15/12, 2014 at 4:29 Comment(3)
I tried your layout (without customviews) and shown the shadow in my phone, could you share a minimal project which reproduce the issue?Brooking
possible duplicate of Android L FAB Button shadowHickox
Related question: #26572548Unkind
R
453

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"
    >
Rubbery answered 17/12, 2014 at 4:7 Comment(13)
Thanks for this! I also found android:clipChildren="false" to be useful when applied to the parent relative layout.Globetrotter
It's so annoying that Google produces such shoddy code. We'll have to account for these framework bugs for years.Filamentous
Great answer, you gave us good insight on how it all works more than simply giving away the solution.Williamwilliams
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.".Kletter
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 https://mcmap.net/q/95356/-elevation-on-android-lollipop-not-workingKaylor
I don't know if it's a bug, but that's true, which is why I wrote android:background="[some non-transparent color]" ;-)Rubbery
In my case it was the transparent color. Ok, transparent things don't cast shadows... hahaOppugn
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-birchWight
@Wight I believe you can also add margin to the element with a shadow instead of padding if you like.Rubbery
Yup. It's a pain anyway xDDDWight
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.Catcall
android:clipToPadding="false" adding to layout worked for meThanatos
@FerranMaylinch setting a nontransparent background color itself solves this.Robbegrillet
B
348

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.

Brasil answered 7/7, 2015 at 14:46 Comment(7)
What a strange thing, Preview showed elevation but real device didn't. Thanks, this one fixed the issue.Crossarm
Works for API level 21 and higherMuslin
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.Nike
This also applies if your background is custom and has no <solid>.Convolvulaceous
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!Antilogy
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.Disharoon
For most of my views, I have rounded corners and this resulted in sharp, non-rounded shadow corners. I found this solution (stackoverflow.com/a/60424218) helpful for elevated views with round corners.Architecture
D
122

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"
Disjunctive answered 30/4, 2016 at 14:10 Comment(1)
It was unexpected. I have set ImageView with src and was looking for solution. Thank you.Radiobiology
F
59

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.

Fredericksburg answered 30/1, 2017 at 13:4 Comment(3)
This does not solve the problem, if you need that flag to be present.Baluchi
thank you!! I spent a day trying to elevate the AppBar and found the issue when I checked the manifest for this activity flagTeetotal
I tried all possible solutions, but none of work for me. This solutions worked. Thanks. Also need android:clipToPadding="false" with this solution.Preengage
C
48

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"
Correlation answered 11/7, 2018 at 12:34 Comment(4)
This solution is the only that works for me. Thank youJameson
This works unless you have a radius on your views background, in which case the shadow will show show as rectangular, but paddedBounds does work for a view with a background.Pout
android:outlineProvider="paddedBounds" this line worked for me. I set Selector Drawable.Preengage
When I used this, shadow is drawn completely inside the view rather than outside, which isn't what I want.Hullda
D
23

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?

Denys answered 2/6, 2017 at 8:24 Comment(1)
This should among the top onesUnwonted
E
12

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>
Ekaterinodar answered 21/10, 2016 at 14:40 Comment(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 :(Josie
H
7

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.

Hearty answered 29/6, 2016 at 9:19 Comment(1)
I set it but it shows sqaure shadow..Person
B
7

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"

    />
Backcross answered 22/9, 2016 at 14:54 Comment(0)
I
4

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

Interfere answered 3/5, 2017 at 10:10 Comment(0)
L
4

For me setting elevation, background and margin worked like a charm.

android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:background="@drawable/card_view" //any drawable or color
android:elevation="4dp"
Liponis answered 16/9, 2021 at 8:31 Comment(0)
R
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));
Reganregard answered 11/3, 2017 at 19:1 Comment(0)
O
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"
Orthotropic answered 16/2, 2018 at 8:40 Comment(0)
L
3

If it still not showing elevation try

    android:hardwareAccelerated="true" 

this will definitely help you.

Limp answered 1/4, 2019 at 7:0 Comment(1)
This fixed it for me. I had assumed that TRUE was the default setting, but apparently not, at least in my case.Halfhardy
P
2

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

Patentor answered 3/5, 2018 at 9:30 Comment(0)
D
1

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

Damnable answered 3/10, 2018 at 13:30 Comment(0)
C
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.

Commitment answered 24/3, 2020 at 15:23 Comment(0)
D
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).

Dishcloth answered 29/1, 2016 at 17:46 Comment(0)
N
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" />
Ngo answered 17/4, 2018 at 9:21 Comment(0)
T
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.

Timotheus answered 18/1, 2019 at 21:42 Comment(0)
F
0

Setting both clipChildren and clipToPadding on parent layout did the job for me

android:clipChildren="false"
android:clipToPadding="false"
Felton answered 25/4, 2022 at 16:28 Comment(0)
M
-2

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

Mongo answered 26/7, 2020 at 17:46 Comment(0)
T
-3

set background color to the layout or view

Thanh answered 10/8, 2020 at 17:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.