Android - 刮刮卡
参考转载至 慕课网 《Android电商活动中的刮刮卡 http://www.imooc.com/view/225》
1、获取canvas 的两种途径
1)onDraw(Canvas canvas); 该回调方法由系统传参
2)new Canvan(mBitmap);
mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mCanvas.drawBitmap(mOverlayBitmap,null,new Rect(0,0,getWidth(),getHeight()),null);
2、实现刮刮卡刮涂效果
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
Dst = 遮盖层,Src = 刮涂路径,DstOut 模式下刮涂路径的像素点值为零;
3、获取图片像素:bitmap.getPixels();
4、自定义View属性
1)values/attr.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="text" format="string"></attr> <attr name="textColor" format="color"></attr> <attr name="textSize" format="dimension"></attr> <declare-styleable name="GuaGuaKa"> <attr name="text"></attr> <attr name="textColor"></attr> <attr name="textSize"></attr> </declare-styleable> </resources>
2) 获取自定义属性
private String mText; //中奖信息文本 private int mTextColor; //中奖信息文本颜色 private int mTextSize; //中奖信息文本大小 TypedArray a = null; a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GuaGuaKa, defStyleAttr, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.GuaGuaKa_text: mText = a.getString(attr); break; case R.styleable.GuaGuaKa_textColor: mTextColor = a.getColor(attr, 0x000000); break; case R.styleable.GuaGuaKa_textSize: mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics())); break; } } if (a != null) a.recycle();
5、完整代码
public class GuaGuaKa extends View { /* 自定义View属性 */ private String mText; //中奖信息文本 private int mTextColor; //中奖信息文本颜色 private int mTextSize; //中奖信息文本大小 private Paint mTextPaint; //中奖信息画笔 private Paint mBrushPaint; //刮涂效果画笔 private Bitmap mBitmap; //刮涂效果图片 private Canvas mCanvas; //刮涂效果画布 private Rect mTextBound; //中奖信息文字区块 private Path mPath; //刮涂效果路径 private Bitmap mOverlayBitmap; //遮盖层图片 private float mLastX, mLastY; private boolean mHasCompleted = false; //刮涂达到预定值既完成 /* 刮涂完成回调接口 */ public interface OnCompletedListener { void OnCompleted(String text); } private OnCompletedListener mOnCompletedListener; public void setOnCompletedListener(OnCompletedListener listener) { this.mOnCompletedListener = listener; } public GuaGuaKa(Context context) { this(context, null); } public GuaGuaKa(Context context, AttributeSet attrs) { this(context, attrs, 0); } public GuaGuaKa(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); //初始化 TypedArray a = null; a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.GuaGuaKa, defStyleAttr, 0); int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.GuaGuaKa_text: mText = a.getString(attr); break; case R.styleable.GuaGuaKa_textColor: mTextColor = a.getColor(attr, 0x000000); break; case R.styleable.GuaGuaKa_textSize: mTextSize = (int) a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 22, getResources().getDisplayMetrics())); break; } } if (a != null) a.recycle(); } private void init(){ mText="谢谢惠顾"; mTextBound=new Rect(); mTextSize=(int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,22,getResources().getDisplayMetrics()); mTextPaint=new Paint(); mBrushPaint=new Paint(); mPath=new Path(); mOverlayBitmap=BitmapFactory.decodeResource(getResources(),R.drawable.fg_guaguaka); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setUpTextPaint(); setUpOverlayPaint(); } /* 设置绘制中奖信息所需对象 */ private void setUpTextPaint() { mTextPaint.setAntiAlias(true); mTextPaint.setStyle(Paint.Style.STROKE); mTextPaint.setTextSize(mTextSize); mTextPaint.setColor(mTextColor); //获得当前画笔绘制文本的宽与高 mTextPaint.getTextBounds(mText, 0, mText.length(), mTextBound); } /* 设置绘制遮盖层所需对象 */ private void setUpOverlayPaint() { mBrushPaint.setAntiAlias(true); mBrushPaint.setDither(true); mBrushPaint.setStrokeJoin(Paint.Join.ROUND); mBrushPaint.setStrokeCap(Paint.Cap.ROUND); mBrushPaint.setStyle(Paint.Style.FILL); mBrushPaint.setStrokeWidth(20); mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); mCanvas = new Canvas(mBitmap); mCanvas.drawBitmap(mOverlayBitmap,null,new Rect(0,0,getWidth(),getHeight()),null); mPath = new Path(); } @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mPath.moveTo(x, y); mLastX = x; mLastY = y; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(x - mLastX); float dy = Math.abs(y - mLastY); if (dx > 3.0f || dy > 3.0f) { mPath.lineTo(x, y); } mLastX = x; mLastY = y; break; case MotionEvent.ACTION_UP: if (!mHasCompleted) { if (calculateCompletedPercent() >= 60) { mHasCompleted = true; postInvalidate(); //完成后回调 if (mOnCompletedListener != null) { mOnCompletedListener.OnCompleted(mText); } } } break; default: return super.onTouchEvent(event); } if (!mHasCompleted) { postInvalidate(); } return true; } @Override protected void onDraw(Canvas canvas) { //绘制中奖信息文本 canvas.drawRect(10, 10, getWidth() - 10, getHeight() - 10, mTextPaint); canvas.translate(getWidth() / 2, getHeight() / 2); canvas.drawText(mText, -mTextBound.width() / 2, mTextBound.height() / 2, mTextPaint); canvas.translate(-getWidth() / 2, -getHeight() / 2); if (!mHasCompleted) { //设置画笔刮涂效果 mBrushPaint.setStyle(Paint.Style.STROKE); mBrushPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); //绘制刮涂路径 mCanvas.drawPath(mPath, mBrushPaint); canvas.drawBitmap(mBitmap, 0, 0, null); } } /* 计算刮涂完成百分比 */ private int calculateCompletedPercent() { int w = mBitmap.getWidth(); int h = mBitmap.getHeight(); float wipeArea = 0; //被擦除的像素 float totalArea = w * h; //所有像素 int percent = 0; int[] pixels = new int[w * h]; //获得bitmap上所有像素信息 mBitmap.getPixels(pixels, 0, w, 0, 0, w, h); for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { int index = j * w + i; if (pixels[index] == 0) { wipeArea++; } } } if (wipeArea > 0 && totalArea > 0) { percent = (int) (wipeArea * 100 / totalArea); } return percent; } }