咱们开发中会经常遇到完成圆角的需求,本文汇总不同场景下常见的一些方案,欢迎补充。

圆角效果实现方式汇总

1.运用shape标签

xml里面运用shape元素完成圆角

<shape xmlns:android="http://schemas.android.com/apk/res/android"
		android:shape="rectangle">
		<corners android:radius="5dp"/>   <!-- 设置圆角弧度 -->
		//<corners android:topRightRadius="8dp" android:topLeftRadius="8dp"/> //各个角不同弧度
		<solid android:color="@color/bg_color"/>   <!-- 设置布景色彩 -->
		<stroke android:color="@color/divider_color" android:width="@dimen/y2"/> <!-- 设置边框色彩以及宽度 -->
	</shape>

优点:

:方便简练直观

缺陷:

:每个xml只要一种款式

:静态图片作为布景适用,如果动态切开就不适宜

2.运用 CardView 、GradientDrawable等现有的图片控件

GradientDrawable方法

	private GradientDrawable gradientDrawable = new GradientDrawable();
		gradientDrawable.setShape(GradientDrawable.RECTANGLE);
		float[] radii = new float[]{//支撑各个角设置不同的弧度
                DisplayUtils.dp2px(this, 10F), DisplayUtils.dp2px(this, 10F),
                0F, 0F,
                0F, 0F,
                DisplayUtils.dp2px(this, 10F), DisplayUtils.dp2px(this, 10F)
        };
        gradientDrawable.setCornerRadii(radii);
	gradientDrawable.setCornerRadius(radius);
	gradientDrawable.setColor(normalColor);
	setBackground(gradientDrawable);

CardView方法

<androidx.cardview.widget.CardView
            android:id="@+id/icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/card_store_normal_margin"
            android:layout_marginBottom="@dimen/card_store_normal_margin"
            app:cardCornerRadius="@dimen/card_store_icon_radius"
            app:cardElevation="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            tools:srcCompat="@tools:sample/avatars">
            <ImageView
                android:id="@+id/app_icon"
                android:layout_width="@dimen/card_store_icon_height"
                android:layout_height="@dimen/card_store_icon_height"
                android:scaleType="centerCrop"
                tools:srcCompat="@tools:sample/avatars" />
 </androidx.cardview.widget.CardView>

优点:

:能够动态设置角弧度

:一起支撑xml或者代码方法界说

缺陷:

:灵活度依然略差

3.运用ViewOutlineProvider裁剪view

ViewOutlineProvider是Android 5.x引入的新特性,用于完成View的阴影和概括

itemView.outlineProvider = object : ViewOutlineProvider() {
		 override fun getOutline(view: View, outline: Outline) {
			outline.setRoundRect(0, 0, view.width, view.height, 5.dp.toFloat())
		 }
	}
// 打开开关
itemView.clipToOutline = true

outline 还能够画其他的一些内容:

outline.setRect(xxx)// 画矩形

outline.setRoundRect(xxx)// 画圆角矩形

outline.setOval(xxx) // 画椭圆

优点:

:比运用了设置drawable的 xml 少了一层过度制作。由于省去了设置的 background

:Outline方法是直接作用于RenderNode,然后再渲染流程中进行过滤,不是对Canvas做切开,因此功率相对于其他几种方法能够更高?

缺陷:

:只能四个角一起装备不支撑每个角单独装备

4.Canvas切开

能够是通过canvas.clipPath切开后制作方针View,也但是先制作方针View后运用Xfermode设置混合形式 制作很自由,能够按照自己的需求切出不同形状,比方能够切出四个圆角不等的作用

clipPath方法:

整个原理就是用Path划出一个圆角矩形区域,调用super.onDraw(canvas)就能够让Drawable 落在那个区域。

@Override
protected void onDraw(Canvas canvas) {
	//设置外框的矩形区域,不可再init()初始化,结构器中width和height还未确定,可在onMesure()中获取并设置
	mRectF = new RectF(0,0, getWidth(),getHeight());
	//path划出一个圆角矩形,容纳图片,图片矩形区域设置比赤色外框小,否则会掩盖住外框,随意控制
	mPath.addRoundRect(new RectF(10, 10, mRectF.right-10,mRectF.bottom-10), 50, 50, Path.Direction.CW);
	canvas.drawRoundRect(mRectF, 50, 50, mPaint); //画出赤色外框圆角矩形
	canvas.clipPath(mPath);//将canvas裁剪到path设定的区域,往后的制作都只能在此区域中,
	//这一句应该放在canvas.clipPath(path)之后,canvas.clipPath(path)只对裁剪之后的制作起作用,
	// 这个方法在ImageView中会画出xml设置的Drawable,落在刚才设置的path中
	super.onDraw(canvas);
}

Xfermode方法:

运用Xfermode的图片渲染合成原理,运用Path结构咱们需求的作用规模,在onDraw的时分,将规模外的一切部分过滤掉

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (clipRect == null || getMeasuredWidth() == 0) {
            clipRect = new RectF(padding, 0, getMeasuredWidth() - padding, getMeasuredHeight());
            maskBitmap = Bitmap.createBitmap(canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_4444);
            Canvas c = new Canvas(maskBitmap);
            //在蒙版上画需求掩盖的图形
            c.drawRoundRect(clipRect, cornerSize, cornerSize, clipPaint);
        }
        //保存还没有制作之前的图层
        int layerId = canvas.saveLayer(clipRect, clipPaint, Canvas.ALL_SAVE_FLAG);
        //制作底部图层
        super.dispatchDraw(canvas);
        //设置混合形式,完成view的四个圆角
        clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        canvas.drawBitmap(maskBitmap, 0, 0, clipPaint);
        clipPaint.setXfermode(null);
        //康复之前的图层,要不然布景是黑色的
        canvas.restoreToCount(layerId);
    }

5.其他第三方库

Glide

	Glide.with(this).load("https://placehoder.com/100")
                .apply(RequestOptions.bitmapTransform(RoundedCorners(20)))
                .into(iv)

fresco