Android设置图片某几个角为圆角

项目里使用的图片加载框架是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 个角中的指定角为圆角
 * <p>
 * 思路是先画一个圆角矩形把这个图片变成圆角,然后想让那个角不是圆角,就把对应角位置那部分的原图画出来即可,画一个矩形就可以把原来的角显示出来,用的方法是drawRect()
 * </p>
 */
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)以及需要哪些角为圆角就可以了。
来张效果图:

完工!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容