Search code examples
androidoverridingimageviewdropshadow

Custom ImageView with drop shadow


Okay, I've been reading and searching around, and am now banging my head against the wall trying to figure this out. Here's what I have so far:

package com.pockdroid.sandbox;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.widget.ImageView;

public class ShadowImageView extends ImageView {

private Rect mRect;
private Paint mPaint;

public ShadowImageView(Context context)
{
    super(context);
    mRect = new Rect();
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setShadowLayer(2f, 1f, 1f, Color.BLACK);
}

@Override
protected void onDraw(Canvas canvas) 
{
    Rect r = mRect;
    Paint paint = mPaint;

    canvas.drawRect(r, paint);
    super.onDraw(canvas);
}

@Override
protected void onMeasure(int w, int h)
{
    super.onMeasure(w,h);
    int mH, mW;
    mW = getSuggestedMinimumWidth() < getMeasuredWidth()? getMeasuredWidth() : getSuggestedMinimumWidth();
    mH = getSuggestedMinimumHeight() < getMeasuredHeight()? getMeasuredHeight() : getSuggestedMinimumHeight();
    setMeasuredDimension(mW + 5, mH + 5);
}

}

The "+5" in the measurements are there as temporary; From what I understand I'll need to do some math to determine the size that the drop shadow adds to the canvas, right?

But when I use this:

public View getView(int position, View convertView, ViewGroup parent) {
    ShadowImageView sImageView;
    if (convertView == null) {
        sImageView = new ShadowImageView(mContext);
        GridView.LayoutParams lp = new GridView.LayoutParams(85, 85);
        sImageView.setLayoutParams(lp);

        sImageView.setScaleType(ImageView.ScaleType.CENTER);
        sImageView.setPadding(5,5,5,5);
    } else {
        sImageView = (ShadowImageView) convertView;
    }

    sImageView.setImageBitmap(bitmapList.get(position));
    return sImageView;
}

in my ImageView, I still get just a normal ImageView when I run the program.

Any thoughts? Thanks.

EDIT: So I spoke with RomainGuy some in the IRC channel, and I have it working now for plain rectangular images with the below code. It still won't draw the shadow directly to my bitmap's transparency though, so I'm still working on that.

@Override
protected void onDraw(Canvas canvas) 
{
    Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.omen);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShadowLayer(5.5f, 6.0f, 6.0f, Color.BLACK);
    canvas.drawColor(Color.GRAY);
    canvas.drawRect(50, 50, 50 + bmp.getWidth(), 50 + bmp.getHeight(), paint);
    canvas.drawBitmap(bmp, 50, 50, null);       
}

Solution

  • Okay, I don't foresee any more answers on this one, so what I ended up going with for now is just a solution for rectangular images. I've used the following NinePatch:

    alt text

    along with the appropriate padding in XML:

    <ImageView
            android:id="@+id/image_test"
            android:background="@drawable/drop_shadow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:paddingLeft="6px"
            android:paddingTop="4px"
            android:paddingRight="8px"
            android:paddingBottom="9px"
            android:src="@drawable/pic1"
            />
    

    to get a fairly good result:

    alt text

    Not ideal, but it'll do.