1 import android.content.Context; 2 import android.content.res.TypedArray; 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapShader; 5 import android.graphics.Canvas; 6 import android.graphics.Color; 7 import android.graphics.Matrix; 8 import android.graphics.Paint; 9 import android.graphics.RectF; 10 import android.graphics.Shader; 11 import android.graphics.drawable.BitmapDrawable; 12 import android.graphics.drawable.ColorDrawable; 13 import android.graphics.drawable.Drawable; 14 import android.util.AttributeSet; 15 import android.widget.ImageView; 16 17 18 public class CircleImageView extends ImageView { 19 20 private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; 21 22 private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; 23 private static final int COLORDRAWABLE_DIMENSION = 1; 24 25 private static final int DEFAULT_BORDER_WIDTH = 0; 26 private static final int DEFAULT_BORDER_COLOR = Color.BLACK; 27 28 private final RectF mDrawableRect = new RectF(); 29 private final RectF mBorderRect = new RectF(); 30 31 private final Matrix mShaderMatrix = new Matrix(); 32 private final Paint mBitmapPaint = new Paint(); 33 private final Paint mBorderPaint = new Paint(); 34 35 private int mBorderColor = DEFAULT_BORDER_COLOR; 36 private int mBorderWidth = DEFAULT_BORDER_WIDTH; 37 38 private Bitmap mBitmap; 39 private BitmapShader mBitmapShader; 40 private int mBitmapWidth; 41 private int mBitmapHeight; 42 43 private float mDrawableRadius; 44 private float mBorderRadius; 45 46 private boolean mReady; 47 private boolean mSetupPending; 48 49 public CircleImageView(Context context) { 50 super(context); 51 } 52 53 public CircleImageView(Context context, AttributeSet attrs) { 54 this(context, attrs, 0); 55 } 56 57 public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 58 super(context, attrs, defStyle); 59 super.setScaleType(SCALE_TYPE); 60 61 TypedArray a = context.obtainStyledAttributes(attrs, 62 R.styleable.CircleImageView, defStyle, 0); 63 64 mBorderWidth = a.getDimensionPixelSize( 65 R.styleable.CircleImageView_border_width, DEFAULT_BORDER_WIDTH); 66 mBorderColor = a.getColor(R.styleable.CircleImageView_border_color, 67 DEFAULT_BORDER_COLOR); 68 69 a.recycle(); 70 71 mReady = true; 72 73 if (mSetupPending) { 74 setup(); 75 mSetupPending = false; 76 } 77 } 78 79 @Override 80 public ScaleType getScaleType() { 81 return SCALE_TYPE; 82 } 83 84 @Override 85 public void setScaleType(ScaleType scaleType) { 86 if (scaleType != SCALE_TYPE) { 87 throw new IllegalArgumentException(String.format( 88 "ScaleType %s not supported.", scaleType)); 89 } 90 } 91 92 @Override 93 protected void onDraw(Canvas canvas) { 94 if (getDrawable() == null) { 95 return; 96 } 97 98 canvas.drawCircle(getWidth() / 2, getHeight() / 2, mDrawableRadius, 99 mBitmapPaint); 100 if (mBorderWidth != 0) { 101 canvas.drawCircle(getWidth() / 2, getHeight() / 2, mBorderRadius, 102 mBorderPaint); 103 } 104 } 105 106 @Override 107 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 108 super.onSizeChanged(w, h, oldw, oldh); 109 setup(); 110 } 111 112 public int getBorderColor() { 113 return mBorderColor; 114 } 115 116 public void setBorderColor(int borderColor) { 117 if (borderColor == mBorderColor) { 118 return; 119 } 120 121 mBorderColor = borderColor; 122 mBorderPaint.setColor(mBorderColor); 123 invalidate(); 124 } 125 126 public int getBorderWidth() { 127 return mBorderWidth; 128 } 129 130 public void setBorderWidth(int borderWidth) { 131 if (borderWidth == mBorderWidth) { 132 return; 133 } 134 135 mBorderWidth = borderWidth; 136 setup(); 137 } 138 139 @Override 140 public void setImageBitmap(Bitmap bm) { 141 super.setImageBitmap(bm); 142 mBitmap = bm; 143 setup(); 144 } 145 146 @Override 147 public void setImageDrawable(Drawable drawable) { 148 super.setImageDrawable(drawable); 149 mBitmap = getBitmapFromDrawable(drawable); 150 setup(); 151 } 152 153 @Override 154 public void setImageResource(int resId) { 155 super.setImageResource(resId); 156 mBitmap = getBitmapFromDrawable(getDrawable()); 157 setup(); 158 } 159 160 private Bitmap getBitmapFromDrawable(Drawable drawable) { 161 if (drawable == null) { 162 return null; 163 } 164 165 if (drawable instanceof BitmapDrawable) { 166 return ((BitmapDrawable) drawable).getBitmap(); 167 } 168 169 try { 170 Bitmap bitmap; 171 172 if (drawable instanceof ColorDrawable) { 173 bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, 174 COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); 175 } else { 176 bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), 177 drawable.getIntrinsicHeight(), BITMAP_CONFIG); 178 } 179 180 Canvas canvas = new Canvas(bitmap); 181 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 182 drawable.draw(canvas); 183 return bitmap; 184 } catch (OutOfMemoryError e) { 185 return null; 186 } 187 } 188 189 private void setup() { 190 if (!mReady) { 191 mSetupPending = true; 192 return; 193 } 194 195 if (mBitmap == null) { 196 return; 197 } 198 199 mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, 200 Shader.TileMode.CLAMP); 201 202 mBitmapPaint.setAntiAlias(true); 203 mBitmapPaint.setShader(mBitmapShader); 204 205 mBorderPaint.setStyle(Paint.Style.STROKE); 206 mBorderPaint.setAntiAlias(true); 207 mBorderPaint.setColor(mBorderColor); 208 mBorderPaint.setStrokeWidth(mBorderWidth); 209 210 mBitmapHeight = mBitmap.getHeight(); 211 mBitmapWidth = mBitmap.getWidth(); 212 213 mBorderRect.set(0, 0, getWidth(), getHeight()); 214 mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, 215 (mBorderRect.width() - mBorderWidth) / 2); 216 217 mDrawableRect.set(mBorderWidth, mBorderWidth, mBorderRect.width() 218 - mBorderWidth, mBorderRect.height() - mBorderWidth); 219 mDrawableRadius = Math.min(mDrawableRect.height() / 2, 220 mDrawableRect.width() / 2); 221 222 updateShaderMatrix(); 223 invalidate(); 224 } 225 226 private void updateShaderMatrix() { 227 float scale; 228 float dx = 0; 229 float dy = 0; 230 231 mShaderMatrix.set(null); 232 233 if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() 234 * mBitmapHeight) { 235 scale = mDrawableRect.height() / (float) mBitmapHeight; 236 dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; 237 } else { 238 scale = mDrawableRect.width() / (float) mBitmapWidth; 239 dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; 240 } 241 242 mShaderMatrix.setScale(scale, scale); 243 mShaderMatrix.postTranslate((int) (dx + 0.5f) + mBorderWidth, 244 (int) (dy + 0.5f) + mBorderWidth); 245 246 mBitmapShader.setLocalMatrix(mShaderMatrix); 247 } 248 249 }
1 <com.sample.CircleImageView
2 android:layout_width="80dp"
3 android:layout_height="80dp"
4 android:layout_marginLeft="40dp"
5 android:scaleType="centerCrop"
6 android:src="@drawable/charming" />