安卓自定义圆形图片控件的使用(hdodenhof/CircleImageView)
Posted 墨血
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓自定义圆形图片控件的使用(hdodenhof/CircleImageView)相关的知识,希望对你有一定的参考价值。
控件的来源:https://github.com/hdodenhof/CircleImageView
感兴趣的可以去看看,我只说一下怎么使用:
效果图:
在自己的项目中使用的话,需要写一个类class CircleImageView extends ImageView :
具体如下,只是使用的话,复制过来就好,注意改一下包名:
1 package de.hdodenhof.circleimageview; 2 3 import android.content.Context; 4 import android.content.res.TypedArray; 5 import android.graphics.Bitmap; 6 import android.graphics.BitmapShader; 7 import android.graphics.Canvas; 8 import android.graphics.Color; 9 import android.graphics.ColorFilter; 10 import android.graphics.Matrix; 11 import android.graphics.Paint; 12 import android.graphics.RectF; 13 import android.graphics.Shader; 14 import android.graphics.drawable.BitmapDrawable; 15 import android.graphics.drawable.ColorDrawable; 16 import android.graphics.drawable.Drawable; 17 import android.net.Uri; 18 import android.support.annotation.ColorInt; 19 import android.support.annotation.ColorRes; 20 import android.support.annotation.DrawableRes; 21 import android.util.AttributeSet; 22 import android.widget.ImageView; 23 24 public class CircleImageView extends ImageView { 25 26 private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; 27 28 private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Config.ARGB_8888; 29 private static final int COLORDRAWABLE_DIMENSION = 2; 30 31 private static final int DEFAULT_BORDER_WIDTH = 0; 32 private static final int DEFAULT_BORDER_COLOR = Color.BLACK; 33 private static final int DEFAULT_FILL_COLOR = Color.TRANSPARENT; 34 private static final boolean DEFAULT_BORDER_OVERLAY = false; 35 36 private final RectF mDrawableRect = new RectF(); 37 private final RectF mBorderRect = new RectF(); 38 39 private final Matrix mShaderMatrix = new Matrix(); 40 private final Paint mBitmapPaint = new Paint(); 41 private final Paint mBorderPaint = new Paint(); 42 private final Paint mFillPaint = new Paint(); 43 44 private int mBorderColor = DEFAULT_BORDER_COLOR; 45 private int mBorderWidth = DEFAULT_BORDER_WIDTH; 46 private int mFillColor = DEFAULT_FILL_COLOR; 47 48 private Bitmap mBitmap; 49 private BitmapShader mBitmapShader; 50 private int mBitmapWidth; 51 private int mBitmapHeight; 52 53 private float mDrawableRadius; 54 private float mBorderRadius; 55 56 private ColorFilter mColorFilter; 57 58 private boolean mReady; 59 private boolean mSetupPending; 60 private boolean mBorderOverlay; 61 private boolean mDisableCircularTransformation; 62 63 public CircleImageView(Context context) { 64 super(context); 65 66 init(); 67 } 68 69 public CircleImageView(Context context, AttributeSet attrs) { 70 this(context, attrs, 0); 71 } 72 73 public CircleImageView(Context context, AttributeSet attrs, int defStyle) { 74 super(context, attrs, defStyle); 75 76 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyle, 0); 77 78 mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_civ_border_width, DEFAULT_BORDER_WIDTH); 79 mBorderColor = a.getColor(R.styleable.CircleImageView_civ_border_color, DEFAULT_BORDER_COLOR); 80 mBorderOverlay = a.getBoolean(R.styleable.CircleImageView_civ_border_overlay, DEFAULT_BORDER_OVERLAY); 81 mFillColor = a.getColor(R.styleable.CircleImageView_civ_fill_color, DEFAULT_FILL_COLOR); 82 83 a.recycle(); 84 85 init(); 86 } 87 88 private void init() { 89 super.setScaleType(SCALE_TYPE); 90 mReady = true; 91 92 if (mSetupPending) { 93 setup(); 94 mSetupPending = false; 95 } 96 } 97 98 @Override 99 public ScaleType getScaleType() { 100 return SCALE_TYPE; 101 } 102 103 @Override 104 public void setScaleType(ScaleType scaleType) { 105 if (scaleType != SCALE_TYPE) { 106 throw new IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType)); 107 } 108 } 109 110 @Override 111 public void setAdjustViewBounds(boolean adjustViewBounds) { 112 if (adjustViewBounds) { 113 throw new IllegalArgumentException("adjustViewBounds not supported."); 114 } 115 } 116 117 @Override 118 protected void onDraw(Canvas canvas) { 119 if (mDisableCircularTransformation) { 120 super.onDraw(canvas); 121 return; 122 } 123 124 if (mBitmap == null) { 125 return; 126 } 127 128 if (mFillColor != Color.TRANSPARENT) { 129 canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mFillPaint); 130 } 131 canvas.drawCircle(mDrawableRect.centerX(), mDrawableRect.centerY(), mDrawableRadius, mBitmapPaint); 132 if (mBorderWidth > 0) { 133 canvas.drawCircle(mBorderRect.centerX(), mBorderRect.centerY(), mBorderRadius, mBorderPaint); 134 } 135 } 136 137 @Override 138 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 139 super.onSizeChanged(w, h, oldw, oldh); 140 setup(); 141 } 142 143 @Override 144 public void setPadding(int left, int top, int right, int bottom) { 145 super.setPadding(left, top, right, bottom); 146 setup(); 147 } 148 149 @Override 150 public void setPaddingRelative(int start, int top, int end, int bottom) { 151 super.setPaddingRelative(start, top, end, bottom); 152 setup(); 153 } 154 155 public int getBorderColor() { 156 return mBorderColor; 157 } 158 159 public void setBorderColor(@ColorInt int borderColor) { 160 if (borderColor == mBorderColor) { 161 return; 162 } 163 164 mBorderColor = borderColor; 165 mBorderPaint.setColor(mBorderColor); 166 invalidate(); 167 } 168 169 /** 170 * @deprecated Use {@link #setBorderColor(int)} instead 171 */ 172 @Deprecated 173 public void setBorderColorResource(@ColorRes int borderColorRes) { 174 setBorderColor(getContext().getResources().getColor(borderColorRes)); 175 } 176 177 /** 178 * Return the color drawn behind the circle-shaped drawable. 179 * 180 * @return The color drawn behind the drawable 181 * 182 * @deprecated Fill color support is going to be removed in the future 183 */ 184 @Deprecated 185 public int getFillColor() { 186 return mFillColor; 187 } 188 189 /** 190 * Set a color to be drawn behind the circle-shaped drawable. Note that 191 * this has no effect if the drawable is opaque or no drawable is set. 192 * 193 * @param fillColor The color to be drawn behind the drawable 194 * 195 * @deprecated Fill color support is going to be removed in the future 196 */ 197 @Deprecated 198 public void setFillColor(@ColorInt int fillColor) { 199 if (fillColor == mFillColor) { 200 return; 201 } 202 203 mFillColor = fillColor; 204 mFillPaint.setColor(fillColor); 205 invalidate(); 206 } 207 208 /** 209 * Set a color to be drawn behind the circle-shaped drawable. Note that 210 * this has no effect if the drawable is opaque or no drawable is set. 211 * 212 * @param fillColorRes The color resource to be resolved to a color and 213 * drawn behind the drawable 214 * 215 * @deprecated Fill color support is going to be removed in the future 216 */ 217 @Deprecated 218 public void setFillColorResource(@ColorRes int fillColorRes) { 219 setFillColor(getContext().getResources().getColor(fillColorRes)); 220 } 221 222 public int getBorderWidth() { 223 return mBorderWidth; 224 } 225 226 public void setBorderWidth(int borderWidth) { 227 if (borderWidth == mBorderWidth) { 228 return; 229 } 230 231 mBorderWidth = borderWidth; 232 setup(); 233 } 234 235 public boolean isBorderOverlay() { 236 return mBorderOverlay; 237 } 238 239 public void setBorderOverlay(boolean borderOverlay) { 240 if (borderOverlay == mBorderOverlay) { 241 return; 242 } 243 244 mBorderOverlay = borderOverlay; 245 setup(); 246 } 247 248 public boolean isDisableCircularTransformation() { 249 return mDisableCircularTransformation; 250 } 251 252 public void setDisableCircularTransformation(boolean disableCircularTransformation) { 253 if (mDisableCircularTransformation == disableCircularTransformation) { 254 return; 255 } 256 257 mDisableCircularTransformation = disableCircularTransformation; 258 initializeBitmap(); 259 } 260 261 @Override 262 public void setImageBitmap(Bitmap bm) { 263 super.setImageBitmap(bm); 264 initializeBitmap(); 265 } 266 267 @Override 268 public void setImageDrawable(Drawable drawable) { 269 super.setImageDrawable(drawable); 270 initializeBitmap(); 271 } 272 273 @Override 274 public void setImageResource(@DrawableRes int resId) { 275 super.setImageResource(resId); 276 initializeBitmap(); 277 } 278 279 @Override 280 public void setImageURI(Uri uri) { 281 super.setImageURI(uri); 282 initializeBitmap(); 283 } 284 285 @Override 286 public void setColorFilter(ColorFilter cf) { 287 if (cf == mColorFilter) { 288 return; 289 } 290 291 mColorFilter = cf; 292 applyColorFilter(); 293 invalidate(); 294 } 295 296 @Override 297 public ColorFilter getColorFilter() { 298 return mColorFilter; 299 } 300 301 private void applyColorFilter() { 302 if (mBitmapPaint != null) { 303 mBitmapPaint.setColorFilter(mColorFilter); 304 } 305 } 306 307 private Bitmap getBitmapFromDrawable(Drawable drawable) { 308 if (drawable == null) { 309 return null; 310 } 311 312 if (drawable instanceof BitmapDrawable) { 313 return ((BitmapDrawable) drawable).getBitmap(); 314 } 315 316 try { 317 Bitmap bitmap; 318 319 if (drawable instanceof ColorDrawable) { 320 bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG); 321 } else { 322 bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), BITMAP_CONFIG); 323 } 324 325 Canvas canvas = new Canvas(bitmap); 326 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 327 drawable.draw(canvas); 328 return bitmap; 329 } catch (Exception e) { 330 e.printStackTrace(); 331 return null; 332 } 333 } 334 335 private void initializeBitmap() { 336 if (mDisableCircularTransformation) { 337 mBitmap = null; 338 } else { 339 mBitmap = getBitmapFromDrawable(getDrawable()); 340 } 341 setup(); 342 } 343 344 private void setup() { 345 if (!mReady) { 346 mSetupPending = true; 347 return; 348 } 349 350 if (getWidth() == 0 && getHeight() == 0) { 351 return; 352 } 353 354 if (mBitmap == null) { 355 invalidate(); 356 return; 357 } 358 359 mBitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); 360 361 mBitmapPaint.setAntiAlias(true); 362 mBitmapPaint.setShader(mBitmapShader); 363 364 mBorderPaint.setStyle(Paint.Style.STROKE); 365 mBorderPaint.setAntiAlias(true); 366 mBorderPaint.setColor(mBorderColor); 367 mBorderPaint.setStrokeWidth(mBorderWidth); 368 369 mFillPaint.setStyle(Paint.Style.FILL); 370 mFillPaint.setAntiAlias(true); 371 mFillPaint.setColor(mFillColor); 372 373 mBitmapHeight = mBitmap.getHeight(); 374 mBitmapWidth = mBitmap.getWidth(); 375 376 mBorderRect.set(calculateBounds()); 377 mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2.0f, (mBorderRect.width() - mBorderWidth) / 2.0f); 378 379 mDrawableRect.set(mBorderRect); 380 if (!mBorderOverlay && mBorderWidth > 0) { 381 mDrawableRect.inset(mBorderWidth - 1.0f, mBorderWidth - 1.0f); 382 } 383 mDrawableRadius = Math.min(mDrawableRect.height() / 2.0f, mDrawableRect.width() / 2.0f); 384 385 applyColorFilter(); 386 updateShaderMatrix(); 387 invalidate(); 388 } 389 390 private RectF calculateBounds() { 391 int availableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 392 int availableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 393 394 int sideLength = Math.min(availableWidth, availableHeight); 395 396 float left = getPaddingLeft() + (availableWidth - sideLength) / 2f; 397 float top = getPaddingTop() + (availableHeight - sideLength) / 2f; 398 399 return new RectF(left, top, left + sideLength, top + sideLength); 400 } 401 402 private void updateShaderMatrix() { 403 float scale; 404 float dx = 0; 405 float dy = 0; 406 407 mShaderMatrix.set(null); 408 409 if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) { 410 scale = mDrawableRect.height() / (float) mBitmapHeight; 411 dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f; 412 } else { 413 scale = mDrawableRect.width() / (float) mBitmapWidth; 414 dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f; 415 } 416 417 mShaderMatrix.setScale(scale, scale); 418 mShaderMatrix.postTranslate((int) (dx + 0.5f) + mDrawableRect.left, (int) (dy + 0.5f) + mDrawableRect.top); 419 420 mBitmapShader.setLocalMatrix(mShaderMatrix); 421 } 422 423 }
到attr.xml中declare-styleable申明自定义控件属性
文件定义在res/values/attr.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 以上是关于安卓自定义圆形图片控件的使用(hdodenhof/CircleImageView)的主要内容,如果未能解决你的问题,请参考以下文章