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