Jin Cao | e096b45 | 2014-07-28 10:49:24 -0700 | [diff] [blame] | 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; |
Jin Cao | 4db8ccc | 2014-07-30 10:11:07 -0700 | [diff] [blame] | 13 | import android.graphics.drawable.Drawable; |
| 14 | import android.graphics.drawable.StateListDrawable; |
Jin Cao | e096b45 | 2014-07-28 10:49:24 -0700 | [diff] [blame] | 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) { |
Jin Cao | 4db8ccc | 2014-07-30 10:11:07 -0700 | [diff] [blame] | 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 | |
Jin Cao | e096b45 | 2014-07-28 10:49:24 -0700 | [diff] [blame] | 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()); |
Jin Cao | 4db8ccc | 2014-07-30 10:11:07 -0700 | [diff] [blame] | 80 | destination.set(getPaddingLeft(), getPaddingTop(), getWidth() - getPaddingRight(), |
| 81 | getHeight() - getPaddingBottom()); |
Jin Cao | e096b45 | 2014-07-28 10:49:24 -0700 | [diff] [blame] | 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 | } |