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