项目里使用的图片加载框架是Universal-Image-Loader,这个框架本身支持设置圆角图片(RoundedBitmapDisplayer),但是不能够指定那几个角设置为圆角,在网上找到了很好的解决方案(详见http://www.2cto.com/kf/201608/539093.html)
其原理很简单,就是根据RoundedBitmapDisplayer的源码,自己又重新实现了一个FlexibleRoundedBitmapDisplayer,允许构造方法传入哪几个角要设置为圆角,着重重写了其子类FlexibleRoundedDrawable 的draw(Canvas canvas)方法,思路先画一个圆角矩形把这个图片变成圆角,然后想让那个角不是圆角,就把对应角位置那部分的原图画出来即可,画一个矩形就可以把原来的角显示出来,用的方法是drawRect()。
完整源码如下,注释很详细了~~~
/**
* Created by July on 2017/5/20.
* Universal-Image-Loader中RoundedBitmapDisplayer的增强版,可以自定义图片 4 个角中的指定角为圆角
*
* 思路是先画一个圆角矩形把这个图片变成圆角,然后想让那个角不是圆角,就把对应角位置那部分的原图画出来即可,画一个矩形就可以把原来的角显示出来,用的方法是drawRect()
*
*/
public class FlexibleRoundedBitmapDisplayer implements BitmapDisplayer
{
protected int cornerRadius;
protected int corners;
// 无圆角,不建议使用
public static final int CORNER_NONE = 0;
// 左上角为圆角
public static final int CORNER_TOP_LEFT = 1;
// 右上角为圆角
public static final int CORNER_TOP_RIGHT = 1 << 1;
// 右下角为圆角
public static final int CORNER_BOTTOM_LEFT = 1 << 2;
// 右下角为圆角
public static final int CORNER_BOTTOM_RIGHT = 1 << 3;
public static final int CORNER_ALL = CORNER_TOP_LEFT | CORNER_TOP_RIGHT | CORNER_BOTTOM_LEFT | CORNER_BOTTOM_RIGHT;
/**
* 构造方法说明:设定圆角像素大小,所有角都为圆角
*
* @param cornerRadiusPixels 圆角像素大小
*/
public FlexibleRoundedBitmapDisplayer(int cornerRadiusPixels)
{
this.cornerRadius = cornerRadiusPixels;
this.corners = CORNER_ALL;
}
/**
* 构造方法说明:设定圆角像素大小,指定角为圆角
*
* @param cornerRadiusPixels 圆角像素大小
* @param corners 自定义圆角 CORNER_NONE 无圆角 CORNER_ALL 全为圆角 CORNER_TOP_LEFT |
* CORNER_TOP_RIGHT | CORNER_BOTTOM_LEFT | CORNER_BOTTOM_RIGHT
* 指定圆角(选其中若干组合 )
*/
public FlexibleRoundedBitmapDisplayer(int cornerRadiusPixels, int corners)
{
this.cornerRadius = cornerRadiusPixels;
this.corners = corners;
}
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom)
{
if (!(imageAware instanceof ImageViewAware))
{
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
}
else
{
imageAware.setImageDrawable(new FlexibleRoundedDrawable(bitmap, cornerRadius, corners));
}
}
public static class FlexibleRoundedDrawable extends Drawable
{
protected final float cornerRadius;
protected final RectF mRect = new RectF(), mBitmapRect;
protected final BitmapShader bitmapShader;
protected final Paint paint;
private int corners;
public FlexibleRoundedDrawable(Bitmap bitmap, int cornerRadius, int corners)
{
this.cornerRadius = cornerRadius;
this.corners = corners;
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapRect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);
}
@Override
protected void onBoundsChange(Rect bounds)
{
super.onBoundsChange(bounds);
mRect.set(0, 0, bounds.width(), bounds.height());
Matrix shaderMatrix = new Matrix();
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
bitmapShader.setLocalMatrix(shaderMatrix);
}
@Override
public void draw(Canvas canvas)
{
// 先画一个圆角矩形将图片显示为圆角
canvas.drawRoundRect(mRect, cornerRadius, cornerRadius, paint);
// 异或,相同为0,不同为1
int notRoundedCorners = corners ^ CORNER_ALL;
// 哪个角不是圆角再用小矩形画出来(原理类似图层加了一个白蒙板,然后用不透明度100%的黑色画笔去在蒙板上绘制,画笔所过之处你原来的图层就会显现出来)
try
{
if ((notRoundedCorners & CORNER_TOP_LEFT) != 0)
{
// 左上角恢复为直角
canvas.drawRect(0, 0, cornerRadius, cornerRadius, paint);
}
if ((notRoundedCorners & CORNER_TOP_RIGHT) != 0)
{
// 右上角恢复为直角
canvas.drawRect(mRect.right - cornerRadius, 0, mRect.right, cornerRadius, paint);
}
if ((notRoundedCorners & CORNER_BOTTOM_LEFT) != 0)
{
// 左下角恢复为直角
canvas.drawRect(0, mRect.bottom - cornerRadius, cornerRadius, mRect.bottom, paint);
}
if ((notRoundedCorners & CORNER_BOTTOM_RIGHT) != 0)
{
// 右下角恢复为直角
canvas.drawRect(mRect.right - cornerRadius, mRect.bottom - cornerRadius, mRect.right, mRect.bottom,
paint);
}
}
catch (Exception e)
{
Log.e("FlexibleRoundedBitmapDisplayer ",e + " ");
}
}
@Override
public int getOpacity()
{
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha)
{
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf)
{
paint.setColorFilter(cf);
}
}
}
那么怎么使用这个类呢?
在使用UIL时给ImageView设置url时,重载一个方法,其中将builder.displayer()的参数改为上面刚封装的FlexibleRoundedBitmapDisplayer就好了,如下:
public void setRoundedImageUrl(String url, int cornerRadius, int corners, int defaultImage, ImageView imageView) {
ImageLoader imageLoader = ImageLoader.getInstance();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(defaultImage).showStubImage(defaultImage)
.showImageForEmptyUri(defaultImage)//url为空时显示的图片
.showImageOnFail(defaultImage)//加载失败显示的图片
.cacheInMemory()//内存缓存
.cacheOnDisc()//磁盘缓存
.displayer(new FlexibleRoundedBitmapDisplayer(cornerRadius, corners))
.build();
imageLoader.displayImage(url, imageView, options);
}
一般项目里都会重新封装ImageView,比如UniversalImageView,那么上述方法放在UniversalImageView类里,参数里就不用传ImageView 了,imageLoader.displayImage(url, imageView, options);中的imageView改成this就好了。
public void setRoundedImageUrl(String url, int cornerRadius, int corners, int defaultImage) {
ImageLoader imageLoader = ImageLoader.getInstance();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(defaultImage).showStubImage(defaultImage)
.showImageForEmptyUri(defaultImage)//url为空时显示的图片
.showImageOnFail(defaultImage)//加载失败显示的图片
.cacheInMemory()//内存缓存
.cacheOnDisc()//磁盘缓存
.displayer(new FlexibleRoundedBitmapDisplayer(cornerRadius, corners))
.build();
imageLoader.displayImage(url, this, options);
}
imageView.setRoundedImageUrl("http://xxx", 22,
FlexibleRoundedBitmapDisplayer.CORNER_TOP_LEFT | FlexibleRoundedBitmapDisplayer.CORNER_TOP_RIGHT);
在给ImageView设置url时,传入圆角的大小(单位px)以及需要哪些角为圆角就可以了。
来张效果图:
完工!