6

I have an ImageView subclass that I use to draw images with rounded corners. The code is based on this answer, and is as follows:

public class ImageViewRoundedCorners extends ImageView {
    ...
    @Override
    protected void onDraw(Canvas canvas) {
        Bitmap scaledBitmap = Bitmap.createBitmap(getMeasuredWidth(),
                                                  getMeasuredHeight(),
                                                  Bitmap.Config.ARGB_8888); 
        Canvas scaledCanvas = new Canvas(scaledBitmap);
        super.onDraw(scaledCanvas); 
        drawRoundedCornerBitmap(canvas, scaledBitmap, 
                                getMeasuredWidth(), getMeasuredHeight());

        scaledBitmap.recycle();
    }

    protected void drawRoundedCornerBitmap(Canvas outputCanvas, Bitmap input, int w, int h) {
        Bitmap output = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        Canvas canvas = new Canvas(output);

        mPaint.reset();
        mPaint.setAntiAlias(true);
        canvas.drawARGB(0, 0, 0, 0);

        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawPath(mClipPath, mPaint);

        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        canvas.drawBitmap(input, 0, 0, mPaint);

        outputCanvas.drawBitmap(output, 0, 0, null);
    }
}

With this code, the image is drawn with properly rounded corners. To avoid the allocations on the first two lines of drawRoundedCornerBitmap, I want to draw directly to outputCanvas, which is the canvas originally passed to onDraw. The new implementation looks like this:

protected void drawRoundedCornerBitmap(...) {
    mPaint.reset();
    mPaint.setAntiAlias(true);
    outputCanvas.drawARGB(0, 0, 0, 0);

    mPaint.setStyle(Paint.Style.FILL);
    outputCanvas.drawPath(mClipPath, mPaint);

    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    outputCanvas.drawBitmap(input, 0, 0, mPaint);
}

For some reason, this code seems to ignore the Porter-Duff mode, and instead just draws the image with normal (non-rounded) corners. Why is this the case? What is it about drawing to an intermediate Bitmap that makes the original code work?

Community
  • 1
  • 1
jnackman
  • 326
  • 4
  • 15

1 Answers1

0

Create a drawable Romain Guy has done this for you. We are not a link factory but his blog post explains it quite extensively and provides an efficient way of doing this. Rounded Corners

The real basic principle, is create a BitmapShader and attach it to a Paint object which draws in a custom Drawable that way you just apply that Drawable to the ImageView.

Using a drawable means that the Image is only painted to a canvas once, meaning that drawing the image is only done once, then all the ImageView does is just scale the drawable.

Chris.Jenkins
  • 13,051
  • 4
  • 60
  • 61
  • Isn't this sort of a pain when you have to scale that drawable in the imageView? The drawable is created, then stretched or cropped, which means your corners are going to look weird, no? – secureboot Oct 08 '13 at 16:37
  • Remember the `ImageView` turns whatever you pass to it into a `Drawable`, provides its size, then calls `draw()` on the `Drawable`. By default if you had a BitmapDrawable it will of course just stretch it, as you pass a `RoundedBitmapDrawable` per-se, it will draw based on that implementation. – Chris.Jenkins Oct 09 '13 at 08:51