图片的圆角矩形效果

建议先阅读:自定义圆角矩形的ImageView

通过Xfermode方式实现

使用画笔Paint去绘制东西,当绘制多个图层叠加的时候,有16种模式。效果如下图。

此处输入图片的描述

模式 说明
PorterDuff.Mode.CLEAR 所有绘制不会绘制到画布上
PorterDuff.Mode.SRC 显示上层绘制图形
PorterDuff.Mode.DST 显示下层绘制图形
PorterDuff.Mode.SRC_OVER 图形叠加,上层盖住下层
PorterDuff.Mode.DST_OVER 图形叠加,下层盖住上层
PorterDuff.Mode.SRC_IN 显示上层交集部分
PorterDuff.Mode.DST_IN 显示下层交集部分
PorterDuff.Mode.SRC_OUT 显示上层非交集部分
PorterDuff.Mode.DST_OUT 显示下层非交集部分
PorterDuff.Mode.SRC_ATOP 显示下层非交集部分和上层交集部分
PorterDuff.Mode.DST_ATOP 显示下层交集部分与上层非交集部分
PorterDuff.Mode.XOR 去除交集部分
PorterDuff.Mode.DARKEN 交集部分颜色加深
PorterDuff.Mode.LIGHTEN 交集部分颜色变亮
PorterDuff.Mode.MULTIPLY 显示交集部分,颜色混合叠加
PorterDuff.Mode.SCREEN 取两图层全部区域,交集部分变为透明色

官方demo中主要绘制代码如下:

1
2
3
4
5
// mDstB是黄色的圆形图bitmap
// mSrcB是蓝色的矩形图bitmap
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint)

可以看到在两个绘制图形过程中,添加Xfermode绘制模式,能够改变两个图的叠加效果,我们主要关注一下SrcIn模式,可以看见,用图层叠加的交集去截取mSrcB图,可以利用这个,想绘制一个圆角的图,然后设置绘制模式,接着绘制一个矩形的图,两者一叠加,正好是用圆角图去截取矩形图,矩形图也就是我们的原图片了。

示例代码如下所示:

activity_main.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">

<ImageView
android:id="@+id/iv_round_image_one"
android:layout_margin="5dp"
android:layout_width="84dp"
android:layout_height="48dp"
/>

</LinearLayout>

dimens.xml:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="round_rect_bitmap_width">84dp</dimen>
<dimen name="round_rect_bitmap_height">48dp</dimen>
</resources>

MainActivity.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public class MainActivity extends AppCompatActivity {

private ImageView mImageViewOne;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mImageViewOne = findViewById(R.id.iv_round_image_one);

Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.logo);

mImageViewOne.setImageBitmap(RoundRectImageTools.toRoundRectA(bitmap,(int)getResources().getDimension(R.dimen.round_rect_bitmap_width),(int)getResources().getDimension(R.dimen.round_rect_bitmap_height),30));


}
}

实现圆形效果的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class RoundRectImageTools {

//对图片裁剪成圆形
public static Bitmap toRoundRectA(Bitmap rawBitmap, int widgetWidth,int widgetHeight,int radius) {

Bitmap bitmap = scaleBitmap(rawBitmap, widgetWidth, widgetHeight);

//指定为 ARGB_4444 可以减小图片大小
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(output);

Paint paint = new Paint();

final int color = 0xff424242;
final Rect rect = new Rect(0, 0,bitmap.getWidth(), bitmap.getHeight());
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);

canvas.drawRoundRect(new RectF(0,0,bitmap.getWidth(),bitmap.getHeight()), radius,radius, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
....
//将头像按比例缩放
private static Bitmap scaleBitmap(Bitmap bitmap,int widgetWidth,int widgetHeight){

//一定要强转成float 不然有可能因为精度不够 出现 scale为0 的错误
float scaleX = (float)widgetWidth/(float)bitmap.getWidth();
float scaleY = (float) widgetHeight / (float) bitmap.getHeight();
Matrix matrix = new Matrix();
matrix.postScale(scaleX, scaleY);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

}
}

最终的效果图:
此处输入图片的描述

通过BitmapShader方式实现

所有的绘制圆角的实现,推荐使用这个方法,不仅仅可以帮助我们实现圆角,连部分圆角都可以实现,比如顶部是两个圆角,底部是两个直角的图片。

首先介绍一下BitmapShader这个类,它作为纹理用于绘制一张图。新图可以是纹理图重复/镜像/边缘像素拉伸而绘制成的新图。这个类构造函数很简单,BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY),第一个参数是Bitmap,作为纹理图传入,tileX是指在水平方向上的绘制方式,tileY是指在竖直方向上的绘制方式。TileMode有三种属性,拉伸、重复、镜像。

  • TileMode.CLAMP 拉伸绘制,并不是指图片拉伸,而是指图片最后一个像素不断绘制,纹理图水平或者竖直方向最后一个像素不断绘制
  • TileMode.REPEAT 重复绘制,在水平或者竖直方向上不断重复绘制纹理图
  • TileMode.MIRROR 镜像绘制,水平或者竖直方向不断的绘制翻转纹理图

使用BitmapShader绘制图的时候,是从画布的左上角开始绘制的。我们是使用拉伸的绘制模式,直接来看一下代码,了解处理过程。

实现圆形效果的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class RoundImageTools {

....

//对图片裁剪成圆形
public static Bitmap toRoundRectB(Bitmap rawBitmap, int widgetWidth,int widgetHeight,int radius) {

Bitmap bitmap = scaleBitmap(rawBitmap, widgetWidth, widgetHeight);

// 初始化绘制纹理图
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

//指定为 ARGB_4444 可以减小图片大小
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(output);

// 初始化画笔
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);

// 利用画笔将纹理图绘制到画布上面
canvas.drawRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, paint);

return output;

}
....

}

通过画布裁剪的方式实现

关于画布裁剪的知识,建议阅读:Canvas的裁剪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class RoundRectImageTools {

....
//对图片裁剪成圆形
public static Bitmap toRoundRectC(Bitmap rawBitmap, int widgetWidth,int widgetHeight,int radius) {

Bitmap bitmap = scaleBitmap(rawBitmap, widgetWidth, widgetHeight);

//指定为 ARGB_4444 可以减小图片大小
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_4444);
Canvas canvas = new Canvas(output);

// 初始化画笔
Paint paint = new Paint();
final int color = 0xff424242;
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);

Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());

Path path = new Path();
path.addRoundRect(new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight()), radius, radius, Path.Direction.CW);
canvas.clipPath(path, Region.Op.INTERSECT);

// 利用画笔将纹理图绘制到画布上面
canvas.drawBitmap(bitmap,rect,rect,paint);

return output;

}
....
}

Demo链接:ImageViews

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器