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 
CircularImageView(Context context)31     public CircularImageView(Context context) {
32         this(context, null, 0);
33     }
34 
CircularImageView(Context context, AttributeSet attrs)35     public CircularImageView(Context context, AttributeSet attrs) {
36         this(context, attrs, 0);
37     }
38 
CircularImageView(Context context, AttributeSet attrs, int defStyle)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
onDraw(Canvas canvas)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      */
drawBitmapWithCircleOnCanvas(Bitmap bitmap, Canvas canvas, RectF source, RectF dest)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 }