之前用到圆角的情况大都是自定义一个shape背景drawable及用到v7包下的CardView包裹View实现圆角矩形效果,还有就是在用户圆形头像的时候需要使用到圆角矩形(圆形可以看做是特殊的圆角矩形),诸如Button,Editext,TextView的圆角矩形颜色背景可以用shape实现,但是ImageView Res圆角还没用到过,它就不能简单地设置一个圆角矩形shape作为背景了。这篇文章将介绍如何自定义一个ImageView实现image圆角矩形的效果及加上Glide和颜色填充的支持。效果如下:
1. 继承AppCompatImageView,初始化
google推荐继承AppCompatImageView实现自定义ImageView实现更好地兼容。
/**
* 默认的圆角大小,单位为dp
*/
private static final float DEFAULT_CORNER = 10;
private Paint mPaint;
private int mCorner;
public RoundRectImageView(Context context) {
this(context,null);
}
public RoundRectImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public RoundRectImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RoundRectImageView);
mCorner = (int) typedArray.getDimension(R.styleable.RoundRectImageView_corner, dp2px(context, DEFAULT_CORNER));
typedArray.recycle();
}
这里自定义了一个属性corner:
<declare-styleable name="RoundRectImageView">
<attr name="corner" format="dimension">attr>
declare-styleable>
2. 重写onDraw(),裁剪图片
/**
* 绘制圆角矩形图片
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if ( drawable != null ) {
Bitmap bitmap = null;
// Drawable转Bitmap
if(drawable instanceof GlideBitmapDrawable) {
bitmap = ((GlideBitmapDrawable)drawable).getBitmap();
} else if(drawable instanceof ColorDrawable){
bitmap = Bitmap.createBitmap(getWidth(),getHeight(),
Config.ARGB_8888);
bitmap.eraseColor(((ColorDrawable) drawable).getColor());//填充颜色
}else{
bitmap = ((BitmapDrawable)drawable).getBitmap();
}
Bitmap roundBitmap = getRoundBitmap(bitmap, mCorner);
final Rect rectSrc = new Rect(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
// 重置画笔,不然会留下黑色区域
mPaint.reset();
canvas.drawBitmap(roundBitmap, rectSrc, rectDest, mPaint);
} else {
super.onDraw(canvas);
}
}
其中的原理是先通过Drawable拿到Bitmap,对Bitmap进行裁剪,然后重绘Bitmap实现圆角矩形的效果。其中裁剪方法为:
/**
* 裁剪图片
* @param bitmap
* @param corner
* @return Bitmap
*/
private Bitmap getRoundBitmap(Bitmap bitmap, int corner) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Rect rect = new Rect(getPaddingLeft(), getPaddingTop(), bitmap.getWidth()-getPaddingRight(), bitmap.getHeight()-getPaddingBottom());
final RectF rectF = new RectF(rect);
mPaint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
mPaint.setColor(Color.WHITE);
canvas.drawRoundRect(rectF, corner, corner, mPaint);
// 设置图像混合模式为SRC_IN,裁剪出我们的圆角Bitmap
mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, mPaint);
return output;
}
其中裁剪原理是通过两个图像进行混合,这里为SRC_IN模式,即可裁剪出我们需要的圆角矩形图像。
完整代码如下:
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import com.bumptech.glide.load.resource.bitmap.GlideBitmapDrawable;
/**
* 自定义圆角矩形ImageView
* Created by LT on 2018/5/13.
*/
public class RoundRectImageView extends AppCompatImageView {
/**
* 默认的圆角大小,单位为dp
*/
private static final float DEFAULT_CORNER = 10;
private Paint mPaint;
private int mCorner;
public RoundRectImageView(Context context) {
this(context,null);
}
public RoundRectImageView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public RoundRectImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.RoundRectImageView);
mCorner = (int) typedArray.getDimension(R.styleable.RoundRectImageView_corner, dp2px(context, DEFAULT_CORNER));
typedArray.recycle();
}
/**
* 绘制圆角矩形图片
*/
@Override
protected void onDraw(Canvas canvas) {
Drawable drawable = getDrawable();
if ( drawable != null ) {
Bitmap bitmap = null;
// Drawable转Bitmap
if(drawable instanceof GlideBitmapDrawable) {
bitmap = ((GlideBitmapDrawable)drawable).getBitmap();
} else if(drawable instanceof ColorDrawable){
bitmap = Bitmap.createBitmap(getWidth(),getHeight(),
Config.ARGB_8888);
bitmap.eraseColor(((ColorDrawable) drawable).getColor());//填充颜色
}else{
bitmap = ((BitmapDrawable)drawable).getBitmap();
}
Bitmap roundBitmap = getRoundBitmap(bitmap, mCorner);
final Rect rectSrc = new Rect(0, 0, roundBitmap.getWidth(), roundBitmap.getHeight());
final Rect rectDest = new Rect(0,0,getWidth(),getHeight());
// 重置画笔,不然会留下黑色区域
mPaint.reset();
canvas.drawBitmap(roundBitmap, rectSrc, rectDest, mPaint);
} else {
super.onDraw(canvas);
}
}
/**
* 裁剪图片
* @param bitmap
* @param corner
* @return Bitmap
*/
private Bitmap getRoundBitmap(Bitmap bitmap, int corner) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(),
bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final Rect rect = new Rect(getPaddingLeft(), getPaddingTop(), bitmap.getWidth()-getPaddingRight(), bitmap.getHeight()-getPaddingBottom());
final RectF rectF = new RectF(rect);
mPaint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
mPaint.setColor(Color.WHITE);
canvas.drawRoundRect(rectF, corner, corner, mPaint);
// 设置图像混合模式为SRC_IN,裁剪出我们的圆角Bitmap
mPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, mPaint);
return output;
}
/**
* dp转 px.
* @param value the value
* @return the int
*/
public static int dp2px(Context context, float value) {
final float scale = context.getResources().getDisplayMetrics().densityDpi;
return (int) (value * (scale / 160) + 0.5f);
}
}