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