CircularBitmapDrawable.java revision 09f46006437e7de33afdb51192bf0bdc08e97040
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; 46ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 47ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public CircularBitmapDrawable(Resources res, 48ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei BitmapCache cache, boolean limitDensity) { 4909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei this(res, cache, limitDensity, null); 5009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 5109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 5209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei public CircularBitmapDrawable(Resources res, 5309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei BitmapCache cache, boolean limitDensity, ExtendedOptions opts) { 5409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei super(res, cache, limitDensity, opts); 55ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 56ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAntiAlias(true); 57ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setFilterBitmap(true); 58ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setDither(true); 59ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 60ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(Color.TRANSPARENT); 61ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStyle(Style.STROKE); 62ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(mBorderWidth); 63ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setAntiAlias(true); 64ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 65ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 66ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 67ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke width of this drawable. 68ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 69ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderWidth(final float borderWidth) { 70ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getStrokeWidth() != borderWidth; 71ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setStrokeWidth(borderWidth); 72ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderWidth = borderWidth; 73ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 74ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 75ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 76ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 77ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 78ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 79ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 80ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Set the border stroke color of this drawable. Set to {@link Color#TRANSPARENT} to disable. 81ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 82ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setBorderColor(final int color) { 83ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final boolean changed = mBorderPaint.getColor() != color; 84ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBorderPaint.setColor(color); 85ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 86ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (changed) { 87ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 88ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 89ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 90ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 91ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 92ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawBitmap(final Canvas canvas, final Rect src, 93ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final Rect dst) { 9409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei onDrawCircularBitmap(getBitmap().bmp, canvas, src, dst, 1f); 9509f46006437e7de33afdb51192bf0bdc08e97040Mark Wei } 9609f46006437e7de33afdb51192bf0bdc08e97040Mark Wei 9709f46006437e7de33afdb51192bf0bdc08e97040Mark Wei @Override 9809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei protected void onDrawPlaceholderOrProgress(final Canvas canvas, 9909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final TileDrawable drawable) { 10009f46006437e7de33afdb51192bf0bdc08e97040Mark Wei BitmapDrawable placeholder = (BitmapDrawable) drawable.getInnerDrawable(); 10109f46006437e7de33afdb51192bf0bdc08e97040Mark Wei Bitmap bitmap = placeholder.getBitmap(); 10209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei float alpha = placeholder.getPaint().getAlpha() / 255f; 10309f46006437e7de33afdb51192bf0bdc08e97040Mark Wei sRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); 10409f46006437e7de33afdb51192bf0bdc08e97040Mark Wei onDrawCircularBitmap(bitmap, canvas, sRect, getBounds(), alpha); 105ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 106ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 107ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei /** 108ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * Call this method with a given bitmap to draw it onto the given canvas, masked by a circular 109ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei * BitmapShader. 110ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei */ 111ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei protected void onDrawCircularBitmap(final Bitmap bitmap, final Canvas canvas, 11209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei final Rect src, final Rect dst, final float alpha) { 113ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Draw bitmap through shader first. 114ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei BitmapShader shader = new BitmapShader(bitmap, TileMode.CLAMP, 115ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei TileMode.CLAMP); 116ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei sMatrix.reset(); 117ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 118ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Fit bitmap to bounds. 119ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei float scale = Math.max((float) dst.width() / src.width(), 120ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei (float) dst.height() / src.height()); 121ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei sMatrix.postScale(scale, scale); 122ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 123ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Translate bitmap to dst bounds. 124ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei sMatrix.postTranslate(dst.left, dst.top); 125ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 126ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei shader.setLocalMatrix(sMatrix); 127ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setShader(shader); 12809f46006437e7de33afdb51192bf0bdc08e97040Mark Wei int oldAlpha = mBitmapPaint.getAlpha(); 12909f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha((int) (oldAlpha * alpha)); 130ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), dst.width() / 2, 131ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint); 13209f46006437e7de33afdb51192bf0bdc08e97040Mark Wei mBitmapPaint.setAlpha(oldAlpha); 133ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 134ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei // Then draw the border. 135ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei canvas.drawCircle(dst.centerX(), dst.centerY(), 136ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei dst.width() / 2f - mBorderWidth / 2, mBorderPaint); 137ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 138ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 139ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 140ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setAlpha(int alpha) { 141ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setAlpha(alpha); 142ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 143ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei final int old = mBitmapPaint.getAlpha(); 144ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mBitmapPaint.setAlpha(alpha); 145ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei if (alpha != old) { 146ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei invalidateSelf(); 147ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 148ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 149ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei 150ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei @Override 151ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei public void setColorFilter(ColorFilter cf) { 152ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei super.setColorFilter(cf); 153ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei mPaint.setColorFilter(cf); 154ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei } 155ad6ca3f895022ded1a11f3eedc50d70ea90cd4daMark Wei} 156