第二步:实现刮开效果。
package com.clock.scratch;
import 。..;
public class ScratchView extends View {
public ScratchView(Context context) {
super(context);
TypedArray typedArray = context.obtainStyledAttributes(R.styleable.ScratchView);
init(typedArray);
}
private void init(TypedArray typedArray) {
mEraseSize = typedArray.getFloat(R.styleable.ScratchView_eraseSize, DEFAULT_ERASER_SIZE);
。..
mErasePaint = new Paint();
mErasePaint.setAntiAlias(true);
mErasePaint.setDither(true);
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//设置擦除效果
mErasePaint.setStyle(Paint.Style.STROKE);
mErasePaint.setStrokeCap(Paint.Cap.ROUND);//设置笔尖形状,让绘制的边缘圆滑
setEraserSize(mEraseSize);
mErasePath = new Path();
ViewConfiguration viewConfiguration = ViewConfiguration.get(getContext());
mTouchSlop = viewConfiguration.getScaledTouchSlop();
}
/**
* 设置橡皮檫尺寸大小(默认大小是 60)
*
* @param eraserSize 橡皮檫尺寸大小
*/
public void setEraserSize(float eraserSize) {
mErasePaint.setStrokeWidth(eraserSize);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
startErase(event.getX(), event.getY());
invalidate();
return true;
case MotionEvent.ACTION_MOVE:
erase(event.getX(), event.getY());
invalidate();
return true;
case MotionEvent.ACTION_UP:
stopErase();
invalidate();
return true;
default:
break;
}
return super.onTouchEvent(event);
}
/**
* 开始擦除
*
* @param x
* @param y
*/
private void startErase(float x, float y) {
mErasePath.reset();
mErasePath.moveTo(x, y);
this.mStartX = x;
this.mStartY = y;
}
/**
* 擦除
*
* @param x
* @param y
*/
private void erase(float x, float y) {
int dx = (int) Math.abs(x - mStartX);
int dy = (int) Math.abs(y - mStartY);
if (dx 》= mTouchSlop || dy 》= mTouchSlop) {
this.mStartX = x;
this.mStartY = y;
mErasePath.lineTo(x, y);
mMaskCanvas.drawPath(mErasePath, mErasePaint);
mErasePath.reset();
mErasePath.moveTo(mStartX, mStartY);
}
}
/**
* 停止擦除
*/
private void stopErase() {
this.mStartX = 0;
this.mStartY = 0;
mErasePath.reset();
}
}
《?xml version=“1.0” encoding=“utf-8”?》
《resources》
《declare-styleable name=“ScratchView”》
《!--擦除尺寸大小--》
《attr name=“eraseSize” format=“float” /》
《/declare-styleable》
《/resources》
上面的代码思路如下:
在 init() 中初始化 mErasePaint 和 mErasePath ,并设置 mErasePaint 的 Xfermode 为 PorterDuff.Mode.CLEAR 用于后面制造出刮奖效果;
重写 onTouchEvent 函数,处理触摸事件 ACTION_DOWN 、 ACTION_MOVE 、 ACTION_UP 等三种事件类型,并利用 mErasePath 记录手指滑动轨迹,再用 mMaskCanvas 将滑动轨迹绘制到第一步生成的 mMaskBitmap 上 ,最后通过调用 invalidate() 引起 View 的重绘生成刮开效果;
为了防止滑动过于灵敏,我们需要对滑动做一个判断就是通过系统提供的 viewConfiguration.getScaledTouchSlop() 获取系统认为的最小滑动距离,当等于或者超过这个距离时,才认为是在滑动,这就是为什么我在 erase() 要加 dx 》= mTouchSlop || dy 》= mTouchSlop 的判断;
为了控制刮痕的粗细,和前面设置刮层的颜色一样,同样为 ScratchView 自定义一个属性 eraseSize 实现在 xml 中控制。同时,在 Java 代码中提供调用方法;
到此,一个基本的刮奖效果已经完成了,我们来看看实现效果如何。

以上两步仅仅完成基础效果而已了,接下来我们来做一些优化。
电子发烧友App








评论