CircularBitmapDrawable.java revision ad6ca3f895022ded1a11f3eedc50d70ea90cd4da
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.bitmap.drawable;
18
19import android.content.res.Resources;
20import android.graphics.Bitmap;
21import android.graphics.BitmapShader;
22import android.graphics.Canvas;
23import android.graphics.Color;
24import android.graphics.ColorFilter;
25import android.graphics.Matrix;
26import android.graphics.Paint;
27import android.graphics.Paint.Style;
28import android.graphics.Rect;
29import android.graphics.Shader.TileMode;
30
31import com.android.bitmap.BitmapCache;
32
33/**
34 * Custom BasicBitmapDrawable implementation for circular images.
35 *
36 * This draws all bitmaps as a circle with an optional border stroke.
37 */
38public class CircularBitmapDrawable extends BasicBitmapDrawable {
39    private static Matrix sMatrix = new Matrix();
40
41    private final Paint mBitmapPaint = new Paint();
42    private final Paint mBorderPaint = new Paint();
43
44    private float mBorderWidth;
45
46    public CircularBitmapDrawable(Resources res,
47            BitmapCache cache, boolean limitDensity) {
48        super(res, cache, limitDensity);
49
50        mBitmapPaint.setAntiAlias(true);
51        mBitmapPaint.setFilterBitmap(true);
52        mBitmapPaint.setDither(true);
53
54        mBorderPaint.setColor(Color.TRANSPARENT);
55        mBorderPaint.setStyle(Style.STROKE);
56        mBorderPaint.setStrokeWidth(mBorderWidth);
57        mBorderPaint.setAntiAlias(true);
58    }
59
60    /**
61     * Set the border stroke width of this drawable.
62     */
63    public void setBorderWidth(final float borderWidth) {
64        final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth;
65        mBorderPaint.setStrokeWidth(borderWidth);
66        mBorderWidth = borderWidth;
67
68        if (changed) {
69            invalidateSelf();
70        }
71    }
72
73    /**
74     * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable.
75     */
76    public void setBorderColor(final int color) {
77        final boolean changed = mBorderPaint.getColor() != color;
78        mBorderPaint.setColor(color);
79
80        if (changed) {
81            invalidateSelf();
82        }
83    }
84
85    @Override
86    protected void onDrawBitmap(final Canvas canvas, final Rect src,
87            final Rect dst) {
88        onDrawCircularBitmap(getBitmap().bmp, canvas, src, dst);
89    }
90
91    /**
92     * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular
93     * BitmapShader.
94     */
95    protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas,
96            final Rect src, final Rect dst) {
97        // Draw bitmap through shader first.
98        BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP,
99                TileMode.CLAMP);
100        sMatrix.reset();
101
102        // Fit bitmap to bounds.
103        float scale = Math.max((float) dst.width() / src.width(),
104                (float) dst.height() / src.height());
105        sMatrix.postScale(scale, scale);
106
107        // Translate bitmap to dst bounds.
108        sMatrix.postTranslate(dst.left, dst.top);
109
110        shader.setLocalMatrix(sMatrix);
111        mBitmapPaint.setShader(shader);
112        canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2,
113                mBitmapPaint);
114
115        // Then draw the border.
116        canvas.drawCircle(dst.centerX(), dst.centerY(),
117                dst.width() / 2f - mBorderWidth / 2, mBorderPaint);
118    }
119
120    @Override
121    public void setAlpha(int alpha) {
122        super.setAlpha(alpha);
123
124        final int old = mBitmapPaint.getAlpha();
125        mBitmapPaint.setAlpha(alpha);
126        if (alpha != old) {
127            invalidateSelf();
128        }
129    }
130
131    @Override
132    public void setColorFilter(ColorFilter cf) {
133        super.setColorFilter(cf);
134        mPaint.setColorFilter(cf);
135    }
136}
137