第二步:實現刮開效果。
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 代碼中提供調用方法;
到此,一個基本的刮獎效果已經完成了,我們來看看實現效果如何。
以上兩步僅僅完成基礎效果而已了,接下來我們來做一些優化。
評論
查看更多