android中Imageview 内的图片圆角的实现方式
此文针对的是 imageview中图片的圆角, 即忽略掉图片的ScaleType, 均对图片采取圆角. 而不是对Imageview本身的圆角.
处理方式分两大类(暂不讨论具体的实现方式)
- 传入图片前将图片圆角化.
- 传入图片之后在绘制过程中进行圆角化处理.
两种实现方式各有优劣.
第一种实现方式在于每次调用之前需要对原图进行圆角化处理, 图片处理一般是比较耗时的操作(大图片比较明显), 而且处理完成后原图就本身带圆角, 不利于获取原来的图片, 此方法同时也是优势.....(无视那些保存原图的小伙伴.....)
第二种方式. 优势在于不需要对图片额外处理, 只需要执行正常的调用逻辑, 是在图片绘制中进行额外处理, 所以时间耗费比方法一少. 不过此种方法处理过的图形本身不带圆角, 只是显示中才有圆角. 而且此种方法实现过程中难点在于获取图片在imageview中的显示位置.
方法二:
步骤一, 对图片的绘制过程进行控制, 需要计算出 imageview 中的图片的显示位置, 然后根据位置进行圆角绘制.
根据imageview中图片的scaletype 不一样, 动态的计算图像在imageview中的位置. 核心代码如下
1 private RectF genBounds() { 2 RectF ret = new RectF(0, 0, 0, 0); 3 4 if (getDrawable() == null) { 5 return ret; 6 } 7 8 int dwidth = getDrawable().getIntrinsicWidth(); 9 int dheight = getDrawable().getIntrinsicHeight(); 10 11 int vwidth = getWidth() - getPaddingLeft() - getPaddingRight(); 12 int vheight = getHeight() - getPaddingTop() - getPaddingBottom(); 13 14 boolean fits = (dwidth < 0 || vwidth == dwidth) && 15 (dheight < 0 || vheight == dheight); 16 17 if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == getScaleType()) { 18 ret.right = vwidth; 19 ret.bottom = vheight; 20 } else { 21 ret = new RectF(0, 0, dwidth, dheight); 22 23 if (ScaleType.MATRIX == getScaleType()) { 24 // Use the specified matrix as-is. 25 } else if (fits) { 26 } else if (ScaleType.CENTER == getScaleType()) { 27 ret.offset((int) ((vwidth - dwidth) * 0.5f + 0.5f), 28 (int) ((vheight - dheight) * 0.5f + 0.5f)); 29 } else if (ScaleType.CENTER_CROP == getScaleType()) { 30 31 float scale; 32 float dx = 0, dy = 0; 33 34 if (dwidth * vheight > vwidth * dheight) { 35 scale = (float) vheight / (float) dheight; 36 dx = (vwidth - dwidth * scale) * 0.5f; 37 } else { 38 scale = (float) vwidth / (float) dwidth; 39 dy = (vheight - dheight * scale) * 0.5f; 40 } 41 42 ret.offset((int) (dx + 0.5f), (int) (dy + 0.5f)); 43 } else if (ScaleType.CENTER_INSIDE == getScaleType()) { 44 float scale; 45 int dx; 46 int dy; 47 48 if (dwidth <= vwidth && dheight <= vheight) { 49 scale = 1.0f; 50 } else { 51 scale = Math.min((float) vwidth / (float) dwidth, 52 (float) vheight / (float) dheight); 53 } 54 55 dx = (int) ((vwidth - dwidth * scale) * 0.5f + 0.5f); 56 dy = (int) ((vheight - dheight * scale) * 0.5f + 0.5f); 57 58 ret.offset(dx, dy); 59 } 60 } 61 62 if (ret.left < getPaddingLeft()) 63 ret.left = getPaddingLeft(); 64 65 if (ret.right > vwidth + getPaddingLeft()) 66 ret.right = vwidth + getPaddingLeft(); 67 68 if (ret.top < getPaddingTop()) ret.top = getPaddingTop(); 69 70 if (ret.bottom > vheight + getPaddingTop()) 71 ret.bottom = vheight + getPaddingTop(); 72 73 return ret; 74 }
步骤二: 对图片的绘制进行处理.
1 private int cornerColor = Color.WHITE; 2 private boolean usrRoundCorner = true; 3 private Path mMaskPath = new Path(); 4 5 private void initPaint() { 6 if (mPaint == null) { 7 mPaint = new Paint(); 8 mPaint.setColor(getCornerColor()); 9 mPaint.setStrokeWidth(3); 10 mPaint.setAntiAlias(true); 11 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); 12 } 13 } 14 15 Paint mPaint; 16 float mCornerRadius = getResources().getDisplayMetrics().density * 3 + 0.5f; 17 float[] radii = new float[]{mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius, mCornerRadius}; 18 19 @Override 20 protected void onDraw(Canvas canvas) { 21 int saveCount = canvas.saveLayerAlpha(0F, 0F, canvas.getWidth(), canvas.getHeight(), 255, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG); 22 super.onDraw(canvas); 23 24 if (usrRoundCorner) { 25 RectF bounds = genBounds(); 26 27 mMaskPath.reset(); 28 mMaskPath.addRoundRect(bounds, radii, Path.Direction.CW); 29 mMaskPath.setFillType(Path.FillType.INVERSE_WINDING); 30 31 canvas.drawPath(mMaskPath, mPaint); 32 } 33 canvas.restoreToCount(saveCount); 34 }
核心代码都在上面了. 大家有其他方法也可以留言告诉我.