Android ImageView 圆角实现

8,881 阅读2分钟

Android开发过程中,ImageView是必不可少的几种控件之一,通常为了美观,图标等内容会设置为圆角,以下简单总结了几种设置圆角的方法。

1. RoundedImageView

RoundImageView为第三方库,在build.gradle(:app)中使用以下语句导入:

implementation 'com.makeramen:roundedimageview:2.3.0'

该控件使用起来也非常方便,圆角设置为10dp示例如下:

<com.makeramen.roundedimageview.RoundedImageView
        android:id="@+id/iv_beauty"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        android:src="@drawable/beauty1"
        app:riv_corner_radius_bottom_left="10dp"
        app:riv_corner_radius_bottom_right="10dp"
        app:riv_corner_radius_top_left="10dp"
        app:riv_corner_radius_top_right="10dp" />

效果如下:

2. CardView

CardView为Android系统自带控件,使用CardView包裹ImageView也可以实现圆角效果,需要注意的是,CardView有可能会影响到控件层级,可以通过设置app:cardElevation="0dp"避免该问题:

<androidx.cardview.widget.CardView
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dp"
        app:cardCornerRadius="10dp"
        app:cardElevation="0dp">
​
        <ImageView
            android:id="@+id/iv_beauty"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/beauty1" />
​
    </androidx.cardview.widget.CardView>

3. Glide

Glide是图片加载常用的控件,通过Glide亦能实现圆角效果,Glide引入:

implementation 'com.github.bumptech.glide:glide:4.13.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.13.0'

代码如下:

RequestOptions options = new RequestOptions().transform(new RoundedCorners(ScreenUtil.dp2px(10)));
Glide.with(this).load(R.drawable.beauty2).apply(options).into(r.ivBeauty);

4. ViewOutlineProvider

通过自定义ViewOutlineProvider也可以实现圆角效果:

public class RoundViewOutlineProvider extends ViewOutlineProvider {
    private final float radius;
    public RoundViewOutlineProvider(float radius) {
        this.radius = radius;
    }

    @Override
    public void getOutline(View view, Outline outline) {
        int leftMargin = 0;
        int topMargin = 0;
        Rect selfRect = new Rect(leftMargin, topMargin, view.getWidth(), view.getHeight());
        outline.setRoundRect(selfRect, radius);
    }
}

使用:

r.ivBeauty.setOutlineProvider(new RoundViewOutlineProvider(ScreenUtil.dp2px(10)));
r.ivBeauty.setClipToOutline(true);

5. 自定义view

对于圆角使用比较多的情况,其实最好的选择是让美术提供附带圆角的切件,可以最大限度避免额外的操作。但是,如果只有非圆角切件且使用地方较多,那么自定义view会是一个不错的选择。

自定义圆角的实现总体上有两种方式,第一种方式是对Bitmap进行操作,第二种方式是对画布进行操作,通过canvas.clipPath完成对画布的裁剪,从而达到圆角的效果。

如果在xml中设置了背景颜色,则通过canvas.clipPath不会生效,此时可以在自定义view种新增一字段,用于绘制背景,在代码中手动调用,自定义view代码如下:

public class RoundedImageView extends AppCompatImageView {

    private Paint paint;
    private Path clipPath;
    private RectF rectF;
    private int radius;
    private int bgColor;

    public RoundedImageView(Context context) {
        this(context, null);
    }

    public RoundedImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        clipPath = new Path();
        rectF = new RectF();
        radius = 0;
        bgColor = 0xFFFFFF;
    }

    public void setRadius(int radius) {
        this.radius = radius;
        invalidate();
    }

    public void setBgColor(int bgColor) {
        this.bgColor = bgColor;
        paint.setColor(bgColor);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        clipPath.reset();
        rectF.set(0, 0, getWidth(), getHeight());
        clipPath.addRoundRect(rectF, radius, radius, Path.Direction.CW);
        // int save = canvas.save();
        canvas.clipPath(clipPath);
        canvas.drawRect(rectF, paint);
        super.onDraw(canvas);
        // canvas.restoreToCount(save);
    }
}

6. 总结

以上简单列举了几种实现圆角的方式。

值得一提的是,如果xml中ImageView scaleType设置成了centerCrop,则上述Glide实现圆角的方式会失效,原因可能是xml scaleType字段加载和Glide应用圆角选项有冲突,感兴趣的读者可以自行研究一下。此时可以去除掉xml中的scaleType属性,通过Glide在实现centerCrop效果的同时达到圆角的目的:

RequestOptions options = new RequestOptions().transform(new CenterCrop());
Glide.with(context)
        .asBitmap()
        .load(beautyResId)
        .apply(options)
        .into(new BitmapImageViewTarget(r.ivBeauty) {
            @Override
            protected void setResource(Bitmap resource) {
                super.setResource(resource);
                RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(context.getResources(), resource);
                roundedBitmapDrawable.setCornerRadius(ScreenUtil.dp2px(8));
                r.ivBeauty.setImageDrawable(roundedBitmapDrawable);
            }
        });