今天闲来无事做,就想着巩固一下 PorterDuffXfermode 的使用吧,先是做了圆形和圆角矩形头像效果,然后就做了个刮刮卡效果。如下图所示
当然 PorterDuffXfermode 的详细使用在这里我就不在强调了,可以去 Google 一下,下面主要来介绍一下效果的实现原理。
其实这个效果十分的简单,主要就是 PorterDuffXfermode 模式的设置和 Paint 的属性设置,下面来看看核心代码
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.testpicture);
mDstBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mSrcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mPath = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setAlpha(0);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(50);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas = new Canvas(mDstBitmap);
mCanvas.drawColor(Color.GRAY);
看看 paint 的属性设置,占了代码的 70%,看看都是哪些效果,
首先设置防锯齿效果,将画笔设置成 stroke 模式并且设置宽度为 50,这么设置有什么用呢?这就决定了我们每次滑动,路径的宽度是多少。
至于 StrokeCap 和 StrokeJoin 的属性就是设置让我们的画笔点下去和滑动的时候造成的效果更圆滑,仔细看看上面的效果演示,是不是路径的两端都是圆弧形状。
将 PorterDuffXfermode 设置成 PorterDuff.Mode.DST_IN 模式,然后调用 Canvas.drawColor() 方法,这个时候实际上我们就是完成绘制一个和图像相同大小的灰色区域,也就是我们将要刮去的部分。
这个时候就很奇怪了,只是在 mDstBitmap 上进行绘制,我们并没有 mSrcBitmap ,更别提进行什么操作了,怎么实现效果呢?实际上这个时候我们可以将 mSrcBitmap 虚拟化出来,就当它是存在的,而且是一个透明图,这也就是为什么我们将 画笔的 Alpha 设置为 0,这样我们每次手指滑动的时候实际上就是在动态增加 mSrcBitmap 的面积,那么我们的mDstBitmap 的灰色区域也就被擦除了。
下面看看 OnDraw() 方法
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawBitmap(mDstBitmap, 0, 0, null);
}
这个时候一定要画 mBitmap 再画 mDstBitmap ,这样的话就像是 图形我已经画出来了,不过被 mDstBitmap 挡住了,这样当我们滑动的时候,不断擦除 mDstBitmap,也就将图形显示出来了。
下面粘贴出源码,实际上,我们还可以测试图的宽度和长度,对当前屏幕进行适配,以免出现图形大于屏幕,部分图形无法显示的问题,实现起来也不是很复杂,所以在此就不讲述。
public class XferModeView extends View {
private Bitmap mBitmap;
private Bitmap mDstBitmap;
private Canvas mCanvas;
private Path mPath;
private Paint paint;
public XferModeView(Context context) {
this(context, null);
}
public XferModeView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public XferModeView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.testpicture);
mDstBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mPath = new Path();
paint = new Paint();
paint.setAntiAlias(true);
paint.setAlpha(0);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(50);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mCanvas = new Canvas(mDstBitmap);
mCanvas.drawColor(Color.GRAY);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, null);
canvas.drawBitmap(mDstBitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(x, y);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(x, y);
break;
}
mCanvas.drawPath(mPath, paint);
invalidate();
return true;
}
}