@946898963
2019-10-04T16:39:05.000000Z
字数 5257
阅读 1138
Android学习笔记
Android绘图
建议先阅读:自定义圆角矩形的ImageView。
使用画笔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中主要绘制代码如下:
// 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:
<?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:
<?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:
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));
}
}
实现圆形效果的代码:
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(Bitmap bitmap, TileMode tileX, TileMode tileY),第一个参数是Bitmap,作为纹理图传入,tileX是指在水平方向上的绘制方式,tileY是指在竖直方向上的绘制方式。TileMode有三种属性,拉伸、重复、镜像。
使用BitmapShader绘制图的时候,是从画布的左上角开始绘制的。我们是使用拉伸的绘制模式,直接来看一下代码,了解处理过程。
实现圆形效果的代码:
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的裁剪。
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