1 package com.android.ex.chips; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.BitmapShader; 6 import android.graphics.Canvas; 7 import android.graphics.Color; 8 import android.graphics.Matrix; 9 import android.graphics.Paint; 10 import android.graphics.RectF; 11 import android.graphics.Shader; 12 import android.graphics.drawable.BitmapDrawable; 13 import android.graphics.drawable.Drawable; 14 import android.graphics.drawable.StateListDrawable; 15 import android.util.AttributeSet; 16 import android.widget.ImageView; 17 18 /** 19 * An ImageView class with a circle mask so that all images are drawn in a 20 * circle instead of a square. 21 */ 22 public class CircularImageView extends ImageView { 23 private static float circularImageBorder = 1f; 24 25 private final Matrix matrix; 26 private final RectF source; 27 private final RectF destination; 28 private final Paint bitmapPaint; 29 private final Paint borderPaint; 30 31 public CircularImageView(Context context) { 32 this(context, null, 0); 33 } 34 35 public CircularImageView(Context context, AttributeSet attrs) { 36 this(context, attrs, 0); 37 } 38 39 public CircularImageView(Context context, AttributeSet attrs, int defStyle) { 40 super(context, attrs, defStyle); 41 42 matrix = new Matrix(); 43 source = new RectF(); 44 destination = new RectF(); 45 46 bitmapPaint = new Paint(); 47 bitmapPaint.setAntiAlias(true); 48 bitmapPaint.setFilterBitmap(true); 49 bitmapPaint.setDither(true); 50 51 borderPaint = new Paint(); 52 borderPaint.setColor(Color.TRANSPARENT); 53 borderPaint.setStyle(Paint.Style.STROKE); 54 borderPaint.setStrokeWidth(circularImageBorder); 55 borderPaint.setAntiAlias(true); 56 } 57 58 @Override 59 protected void onDraw(Canvas canvas) { 60 Drawable drawable = getDrawable(); 61 BitmapDrawable bitmapDrawable = null; 62 // support state list drawable by getting the current state 63 if (drawable instanceof StateListDrawable) { 64 if (((StateListDrawable) drawable).getCurrent() != null) { 65 bitmapDrawable = (BitmapDrawable) drawable.getCurrent(); 66 } 67 } else { 68 bitmapDrawable = (BitmapDrawable) drawable; 69 } 70 71 if (bitmapDrawable == null) { 72 return; 73 } 74 Bitmap bitmap = bitmapDrawable.getBitmap(); 75 if (bitmap == null) { 76 return; 77 } 78 79 source.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); 80 destination.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), 81 getHeight() - getPaddingBottom()); 82 83 drawBitmapWithCircleOnCanvas(bitmap, canvas, source, destination); 84 } 85 86 /** 87 * Given the source bitmap and a canvas, draws the bitmap through a circular 88 * mask. Only draws a circle with diameter equal to the destination width. 89 * 90 * @param bitmap The source bitmap to draw. 91 * @param canvas The canvas to draw it on. 92 * @param source The source bound of the bitmap. 93 * @param dest The destination bound on the canvas. 94 */ 95 public void drawBitmapWithCircleOnCanvas(Bitmap bitmap, Canvas canvas, 96 RectF source, RectF dest) { 97 // Draw bitmap through shader first. 98 BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, 99 Shader.TileMode.CLAMP); 100 matrix.reset(); 101 102 // Fit bitmap to bounds. 103 matrix.setRectToRect(source, dest, Matrix.ScaleToFit.FILL); 104 105 shader.setLocalMatrix(matrix); 106 bitmapPaint.setShader(shader); 107 canvas.drawCircle(dest.centerX(), dest.centerY(), dest.width() / 2f, 108 bitmapPaint); 109 110 // Then draw the border. 111 canvas.drawCircle(dest.centerX(), dest.centerY(), 112 dest.width() / 2f - circularImageBorder / 2, borderPaint); 113 } 114 }