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