您的位置:首页 > 移动开发 > Android开发

Android中的自绘View的那些事儿(六)之 画布裁剪

2017-12-22 10:53 531 查看
我们在之前的文章中有简单介绍过画布Canvas的使用,它可以使用一系列的draw方法来绘制出各种样式的几何的图形、文字和图片来。今天我们继续探讨Canvas的另一种使用,那就是画布裁剪。什么是画布裁剪?它有点像flash 遮罩层的概念,说白了就是把原来一整块画布裁剪部分出来,然后要绘制出来的东西只能在指定的裁剪区域范围内才能显示出来。

Canvas的裁剪必须要使用save和restore方法:

save: 用于保存Canvas当前的状态。save之后,我们便可以随意对Canvas进行平移、放缩、旋转、错切、裁剪等操作

restore: 用于恢复Canvas之前保存的状态。也就是使save后对Canvas执行的操作对后续的绘制不会造成影响

Canvas的裁剪提供了一些的clip方法:

clipRegion 方法已经不再建议使用

clipPath    裁剪路径,就是指在此路径内绘制

clipRect    裁剪矩形,就是指在此矩形内绘制

示例:

public class MyView extends View {
public MyView(Context context) {
this(context, null, 0);
}

public MyView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}

public MyView(Context context, @Nullable AttributeSet attrs, intdefStyleAttr) {
super(context, attrs, defStyleAttr);
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
canvas.drawBitmap(bitmap, 0, 0, paint);
}
}
我们首先来看下正常情况下,我们只在canvas中绘制一张图片。输出效果:



修改onDraw代码:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);

int centerX = getWidth() / 2;
int centerY = getHeight() / 2;

canvas.save();

Path path = new Path();
path.addCircle(centerX, centerY, 300, Path.Direction.CW);
canvas.clipPath(path);
canvas.clipRect(centerX - 50, 100, centerX + 50, getHeight() - 100,Region.Op.UNION);

Bitmap bitmap =BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
canvas.drawBitmap(bitmap, 0, 0, paint);

canvas.restore();
}
代码中,我们在开头和结尾分别使用了canvas.save();和canvas.restore();。然后来看中间部分,canvas.clipPath()和canvas.clipRect()两次裁剪了画布。注意clipRect最后的参数Region.Op.UNION,它是表示两个区域叠加。运行效果:



再修改onDraw代码:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);

int centerX = getWidth() / 2;
int centerY = getHeight() / 2;

canvas.save();

Path path = new Path();
path.addCircle(centerX, centerY, 300, Path.Direction.CW);
canvas.clipPath(path);
canvas.clipRect(centerX - 50, 100, centerX + 50, getHeight() - 100,Region.Op.UNION);

canvas.rotate(45, centerX, centerY); // 旋转
canvas.translate(100, 100); // 平移
canvas.scale(0.5f, 0.5f); // 缩放
canvas.skew(0, 1); // 错切

Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.iron_man);
canvas.drawBitmap(bitmap, 0, 0, paint);

canvas.restore();
}
本次代码中,我们加入了旋转(rotate)、平移(translate)、缩放(scale)以及错切(skew)效果。运行效果:



注意

在Android4.0及之前的手机中,因为硬件加速等原因,在使用clipPath时很有可能会发生UnsupportedOperationException异常,像下面:

java.lang.UnsupportedOperationException
atandroid.view.GLES20Canvas.clipPath(GLES20Canvas.java:287)
atcom.myapp.MyCustomView.onDraw(SourceFile:288)
at android.view.View.draw(View.java:9310)
at android.view.View.getDisplayList(View.java:8773)
atandroid.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2298)
所以在使用画布裁剪中最好加入捕捉UnsupportedOperationException异常的处理和系统判断过滤。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息