实现圆形imageview,一般有两种方法,通过BitmapShader和Xfermode.实现起来都比较简单,主要是有些细节方面的东西要注意。
1.通过BitmapShader实现,主要代码如下
private Paint getShaderPaint(Bitmap bitmap) {
Bitmap scaleBitmap = getScaleBitmap(bitmap, radius);
BitmapShader bitmapShader = new BitmapShader(scaleBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(bitmapShader);
paint.setAntiAlias(true);
return paint;
}
canvas.drawCircle(width / 2, height / 2, radius, getShaderPaint(bitmap));
这种方法就是通过bitmap生成BitmapShader,将生成的bitmapShader设给Paint,在ondraw()中用这个paint画一个circle。
要注意的是getShaderPaint()中的第一行代码
Bitmap scaleBitmap = getScaleBitmap(bitmap, radius);
这行代码是会将原始的bitmap对象做缩放和裁剪,保证最终显示的图片比较正常,否则,如果bitmap的大小和view的大小不一样,会导致显示的图片看起来比较奇怪,具体的效果大家试下就知道了。getScaleBitmap()方法会在最下面给出。
2.通过Xfermode实现,主要代码如下
private Bitmap getRoundBitmap(Bitmap bitmap) {
Bitmap scaleBitmap = getScaleBitmap(bitmap, radius);
Bitmap out = Bitmap.createBitmap(scaleBitmap.getWidth(), scaleBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
Rect rect = new Rect(0, 0, scaleBitmap.getWidth(), scaleBitmap.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(scaleBitmap.getWidth() / 2, scaleBitmap.getHeight() / 2, scaleBitmap.getWidth() / 2, paint);
paint.setXfermode(SRC_IN);
canvas.drawBitmap(scaleBitmap, rect, rect, paint);
paint.reset();
return out;
}
canvas.drawBitmap(getRoundBitmap(bitmap), rect, rect, paint);
这种方法原理是: new 一个bitmap,用这个bitmap生成一个canvas,在canvas上先画一个circle,在设置paint的Xfermode为PorterDuff.Mode.SRC_IN,再画bitmap,这样就可以得到一个圆形的bitmap,再在ondraw()中drawBitmap()时使用这个圆形的bitmap。
这种方法看起来也比较好理解,要注意的是getRoundBitmap()中使用的Paint如果是类的成员变量,在方法的最后要调用paint.reset(),否则可能会导致最终画出来的图片有黑色的背景。最简单的方法是getRoundBitmap()中new一个Paint临时变量,不使用类的成员变量paint
下面是一个完整的实现类
public class CircleImageView extends ImageView {
private static PorterDuffXfermode SRC_IN = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);//取两层绘制交集。显示上层。
private int width;
private int height;
private Rect rect;
private Paint paint;
private int radius;
public CircleImageView(Context context) {
this(context, null);
}
public CircleImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
rect = new Rect(0, 0, w, h);
width = w;
height = h;
radius = Math.min(width, height) / 2;
}
@Override
protected void onDraw(Canvas canvas) {
//xml中要用src,不能用background,否则这里drawable会为null
Drawable drawable = getDrawable();
if (drawable == null) {
return;
}
Bitmap bitmap = null;
if (drawable instanceof BitmapDrawable) {
bitmap = ((BitmapDrawable) drawable).getBitmap();
}
if (bitmap == null) {
return;
}
//通过给Paint设置BitmapShader的方式画圆形图
canvas.drawCircle(width / 2, height / 2, radius, getShaderPaint(bitmap));
//通过设置Xfermode的方式获取圆形Bitmap来实现圆形图
canvas.drawBitmap(getRoundBitmap(bitmap), rect, rect, paint);
}
private Paint getShaderPaint(Bitmap bitmap) {
Bitmap scaleBitmap = getScaleBitmap(bitmap, radius);
BitmapShader bitmapShader = new BitmapShader(scaleBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
paint.setShader(bitmapShader);
paint.setAntiAlias(true);
return paint;
}
private Bitmap getRoundBitmap(Bitmap bitmap) {
Bitmap scaleBitmap = getScaleBitmap(bitmap, radius);
Bitmap out = Bitmap.createBitmap(scaleBitmap.getWidth(), scaleBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(out);
Rect rect = new Rect(0, 0, scaleBitmap.getWidth(), scaleBitmap.getHeight());
paint.setAntiAlias(true);
paint.setFilterBitmap(true);
paint.setDither(true);
canvas.drawARGB(0, 0, 0, 0);
canvas.drawCircle(scaleBitmap.getWidth() / 2, scaleBitmap.getHeight() / 2, scaleBitmap.getWidth() / 2, paint);
paint.setXfermode(SRC_IN);
canvas.drawBitmap(scaleBitmap, rect, rect, paint);
paint.reset();
return out;
}
private Bitmap getScaleBitmap(Bitmap bitmap, int radius) {
Bitmap scaledSrcBmp;
int diameter = radius * 2;
// 为了防止宽高不相等,造成圆形图片变形,因此截取长方形中处于中间位置最大的正方形图片
int bmpWidth = bitmap.getWidth();
int bmpHeight = bitmap.getHeight();
int squareWidth = 0, squareHeight = 0;
int x = 0, y = 0;
Bitmap squareBitmap;
if (bmpHeight > bmpWidth) {// 高大于宽
squareWidth = squareHeight = bmpWidth;
x = 0;
y = (bmpHeight - bmpWidth) / 2;
// 截取正方形图片
squareBitmap = Bitmap.createBitmap(bitmap, x, y, squareWidth, squareHeight);
} else if (bmpHeight < bmpWidth) {// 宽大于高
squareWidth = squareHeight = bmpHeight;
x = (bmpWidth - bmpHeight) / 2;
y = 0;
squareBitmap = Bitmap.createBitmap(bitmap, x, y, squareWidth, squareHeight);
} else {
squareBitmap = bitmap;
}
if (squareBitmap.getWidth() != diameter || squareBitmap.getHeight() != diameter) {
scaledSrcBmp = Bitmap.createScaledBitmap(squareBitmap, diameter, diameter, true);
} else {
scaledSrcBmp = squareBitmap;
}
return scaledSrcBmp;
}
}