Search code examples
androidgraphicsandroid-custom-view

Efficiency when drawing an ImageView with rounded corners


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?


Solution

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