39

I have done some extensive searching for code examples on this but cannot find anything.

In particular, I am looking to add a shadow to a png drawable I am using in an ImageView. This png drawable is a rounded rect with transparent corners.

Can somebody please provide a code example of how to add a decent drop shadow to a view either in code or XML?

coneybeare
  • 33,113
  • 21
  • 131
  • 183
  • 1
    you can easily generate ninepatch shadow using this tool http://inloop.github.io/shadow4android/ – Yuraj Dec 13 '14 at 13:07

5 Answers5

35

You could use a combination of Bitmap.extractAlpha and a BlurMaskFilter to manually create a drop shadow for any image you need to display, but that would only work if your image is only loaded/displayed once in a while, since the process is expensive.

Pseudo-code (might even compile!):

BlurMaskFilter blurFilter = new BlurMaskFilter(5, BlurMaskFilter.Blur.OUTER);
Paint shadowPaint = new Paint();
shadowPaint.setMaskFilter(blurFilter);

int[] offsetXY = new int[2];
Bitmap shadowImage = originalBitmap.extractAlpha(shadowPaint, offsetXY);

/* Might need to convert shadowImage from 8-bit to ARGB here, can't remember. */

Canvas c = new Canvas(shadowImage);
c.drawBitmap(originalBitmap, offsetXY[0], offsetXY[1], null);

Then put shadowImage into your ImageView. If this image never changes but is display a lot, you could create it and cache it in onCreate to bypass the expensive image processing.

Even if that doesn't work as is, it should be enough to get you going in the right direction.

Sri Harsha Chilakapati
  • 11,744
  • 6
  • 50
  • 91
Josh
  • 10,618
  • 2
  • 32
  • 36
  • 3
    It sort of worked… Once I changed the offsetXY[[0] and [1] in the drawBitmap to be negative of those values it lined up correctly. However, the original bitmap is drawing as a solid black image. http://cl.ly/77e6b7839c1ffc94c1e0 How to fix? – coneybeare Aug 26 '10 at 02:40
  • Not sure without seeing code. Try checking the bitdepths of the source and destination bitmaps. The problem might be that you're drawing a 32-bit image (the original) onto an 8-bit image (the extracted shadowImage). If that's the case, do something like Bitmap shadowImage32 = shadowImage.copy(ARGB_8888, true) up where I have the convert comment, and draw onto that guy instead of the 8-bit shadowImage. – Josh Aug 27 '10 at 13:55
  • Hello @Josh I am using your code. Its working but how can we change shadow color ? – Hardik Joshi May 09 '13 at 10:00
  • 1
    Replace the null in that last drawBitmap line with a Paint that uses a ColorFilter. See http://stackoverflow.com/questions/3499095/how-do-you-tint-a-bitmap-in-android for an example. – Josh May 09 '13 at 13:33
  • just want to point out the blur is done to *entire* shadowImage, just to get the drop shadow gradient on the edges, it's not very efficient. – Helin Wang Dec 10 '14 at 00:08
  • 1
    Do you have a better suggestion for creating a drop shadow on an arbitrary image, Helin? – Josh Dec 10 '14 at 15:41
29

For Drop shadow use below code

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  <gradient
    android:startColor="#ffffff"
    android:centerColor="#d3d7cf"
    android:endColor="#2e3436"
    android:angle="90" />
</shape>

Use above drawable for a background of a view

<View 
    android:id="@+id/divider" 
    android:background="@drawable/black_white_gradient"
    android:layout_width="match_parent" 
    android:layout_height="10sp"
    android:layout_below="@+id/buildingsList"/>
Thierry Roy
  • 8,452
  • 10
  • 60
  • 84
om252345
  • 2,395
  • 4
  • 29
  • 31
  • 9
    This isn't explained as well as it could be, but it's not an entirely bad approach. The key point is that the view with the gradient as a background is a separate view that should be positioned immediately below the view that you want the shadow to appear on. This works best when the view to be shadowed takes up the full width of the screen, otherwise the corners will look wrong. – Tim Martin May 26 '12 at 10:23
  • This is an approach for declarative situations, but in my case I create a dynamic number of buttons in code depending on data read, so it's not much use for my case. – jrichview Apr 11 '16 at 19:08
14

This helped me to get the shadow working so I wanted to share the working code:

private Bitmap createShadowBitmap(Bitmap originalBitmap) {
    BlurMaskFilter blurFilter = new BlurMaskFilter(5, BlurMaskFilter.Blur.OUTER);
    Paint shadowPaint = new Paint();
    shadowPaint.setMaskFilter(blurFilter);

    int[] offsetXY = new int[2];
    Bitmap shadowImage = originalBitmap.extractAlpha(shadowPaint, offsetXY);

    /* Need to convert shadowImage from 8-bit to ARGB here. */
    Bitmap shadowImage32 = shadowImage.copy(Bitmap.Config.ARGB_8888, true);
    Canvas c = new Canvas(shadowImage32);
    c.drawBitmap(originalBitmap, -offsetXY[0], -offsetXY[1], null);

    return shadowImage32;
}
PeterE
  • 163
  • 1
  • 7
8

For API 21(5.0)+ add android:elevation="4dp" or android:translationZ="4dp" to view description. Documentation

Elevation Attribute

Artyom
  • 851
  • 11
  • 15
1

Always use Transparent shadow such that they could stick to any color.

shadow.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
  <gradient
    android:startColor="#002e3436"
    android:endColor="#992e3436"
    android:angle="90" />
</shape>

And in View

<View 
    android:id="@+id/divider" 
    android:background="@drawable/shadow"
    android:layout_width="match_parent" 
    android:layout_height="5dp"/>
Pradeep Kumar Kushwaha
  • 2,231
  • 3
  • 23
  • 34