CircularBitmapDrawable.java revision 5c102db5a1a16a2adcc7728693a6e65a981f91ae
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; 3009f46006437e7de33afdb51192bf0bdc08e97040Mark Weiimport android.graphics.drawable.BitmapDrawable; 31ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 32ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Weiimport com.android.bitmap.BitmapCache; 33ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 34ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei/** 35ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Custom BasicBitmapDrawable implementation for circular images. 36ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * 37ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * This draws all bitmaps as a circle with an optional border stroke. 38ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 3909f46006437e7de33afdb51192bf0bdc08e97040Mark Weipublic class CircularBitmapDrawable extends ExtendedBitmapDrawable { 40ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private static Matrix sMatrix = new Matrix(); 41ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 42ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mBitmapPaint = new Paint(); 43ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private final Paint mBorderPaint = new Paint(); 44ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 45ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei private float mBorderWidth; 46df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei private Bitmap mShaderBitmap; 47ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 48ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public CircularBitmapDrawable(Resources res, 49ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei BitmapCache cache, boolean limitDensity) { 5009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei this(res, cache, limitDensity, null); 5109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 5209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 5309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei public CircularBitmapDrawable(Resources res, 5409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei BitmapCache cache, boolean limitDensity, ExtendedOptions opts) { 5509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei super(res, cache, limitDensity, opts); 56ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 57ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAntiAlias(true); 58ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setFilterBitmap(true); 59ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setDither(true); 60ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 61ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(Color.TRANSPARENT); 62ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStyle(Style.STROKE); 63ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(mBorderWidth); 64ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setAntiAlias(true); 65ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 66ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 67ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 68ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke width of this drawable. 69ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 70ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderWidth(final float borderWidth) { 71ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth; 72ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(borderWidth); 73ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderWidth = borderWidth; 74ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 75ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 76ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 77ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 78ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 79ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 80ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 81ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable. 82ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 83ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderColor(final int color) { 84ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getColor() != color; 85ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(color); 86ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 87ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 88ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 89ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 90ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 91ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 92ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 93ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawBitmap(final Canvas canvas, final Rect src, 94ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final Rect dst) { 9509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei onDrawCircularBitmap(getBitmap().bmp, canvas, src, dst, 1f); 9609f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 9709f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 9809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei @Override 9909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei protected void onDrawPlaceholderOrProgress(final Canvas canvas, 10009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final TileDrawable drawable) { 10109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei BitmapDrawable placeholder = (BitmapDrawable) drawable.getInnerDrawable(); 10209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei Bitmap bitmap = placeholder.getBitmap(); 10309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei float alpha = placeholder.getPaint().getAlpha() / 255f; 10409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei sRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); 10509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei onDrawCircularBitmap(bitmap, canvas, sRect, getBounds(), alpha); 106ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 107ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 108ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 109ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular 110ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * BitmapShader. 111ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 112ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, 1138dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei final Rect src, final Rect dst) { 1148dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei onDrawCircularBitmap(bitmap, canvas, src, dst, 1f); 1158dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei } 1168dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei 1178dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei /** 1188dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular 1198dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei * BitmapShader. The alpha parameter is the value from 0f to 1f to attenuate the alpha by. 1208dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei */ 1218dd5cac690e42383d6bfc20af04eb781abd14f54Mark Wei protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, 12209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final Rect src, final Rect dst, final float alpha) { 123ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw bitmap through shader first. 124df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei BitmapShader shader = (BitmapShader) mBitmapPaint.getShader(); 125df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei if (shader == null || mShaderBitmap != bitmap) { 126df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei shader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP); 127df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei mShaderBitmap = bitmap; 128df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei } 129ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 130df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei sMatrix.reset(); 131ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Fit bitmap to bounds. 132ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float scale = Math.max((float) dst.width() / src.width(), 133ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei (float) dst.height() / src.height()); 134ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei sMatrix.postScale(scale, scale); 135ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Translate bitmap to dst bounds. 136ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei sMatrix.postTranslate(dst.left, dst.top); 137ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei shader.setLocalMatrix(sMatrix); 1385c102db5a1a16a2adcc7728693a6e65a981f91aeLeon Scroggins III mBitmapPaint.setShader(shader); 139df01966f999ddcc69b3e479c9efbd733ad86bc84Mark Wei 14009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei int oldAlpha = mBitmapPaint.getAlpha(); 14109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha((int) (oldAlpha * alpha)); 142ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2, 143ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint); 14409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha(oldAlpha); 145ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 146ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Then draw the border. 147ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), 148ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei dst.width() / 2f - mBorderWidth / 2, mBorderPaint); 149ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 150ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 151ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 152ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setAlpha(int alpha) { 153ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setAlpha(alpha); 154ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 155ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final int old = mBitmapPaint.getAlpha(); 156ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAlpha(alpha); 157ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (alpha != old) { 158ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 159ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 160ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 161ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 162ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 163ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setColorFilter(ColorFilter cf) { 164ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setColorFilter(cf); 165ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mPaint.setColorFilter(cf); 166ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 167ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei} 168