每日一学(二)刮刮卡效果实现
程序员文章站
2024-02-02 12:42:10
...
一、原理及分析
1、核心原理:xfermode
xfermode是android绘图过程中用来处理两张图片叠加效果的,关于它的详细介绍请移步:http://blog.csdn.net/iispring/article/details/50472485 这篇博客里详细讲解了xfermode的实现原理、用法及使用过程中的坑。
ps: 圆角图片、圆形头像也是可以用xfermode实现的,省时省力呐!
2、实现过程分析
刮刮卡共分为两层,底层是奖项,这里假定为一张图片,上层是刮奖涂层,我们在屏幕上刮奖的过程,是处理onTouch事件,在底层的奖项图片上实时绘制我们的滑动路径,关键点就在于,在绘制我们的滑动路径之前,设置xfermode,取两张图片的交集部分且显示奖项层。这样就实现了我们在刮奖的时候,一点一点的显示奖项层。同时每一次抬起手指的时候计算 刮奖涂层里空白像素的面积,当达到一定的比例时,只绘制奖项层,这样这实现了奖项层的完全展示。
二、代码实现
知道了原理,实现起来就简单啦!这里先放一张效果图
我们自定义的刮刮卡View核心代码如下:
package com.bec.scratchcard;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Xfermode;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* 刮刮卡View
* Created by ZGP on 2017/6/7.
*/
public class ScratchCardView extends View {
private Bitmap mBitmap, mBackBitmap;
private Paint mPaint, mBackPint;
private Path mPath;
private int mLastX;
private int mLastY;
private boolean isComplete;
private Xfermode mXfermode;
/**
* 绘制线条的Paint,即用户手指绘制Path
*/
private Paint mOutterPaint;
private Rect mTextBound;
/**
* 内存中创建的Canvas
*/
private Canvas mCanvas;
private String mText = "一等奖";
private CountThread mCountThread;
public ScratchCardView(Context context) {
super(context);
init();
}
public ScratchCardView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mCountThread = new CountThread();
mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
mPaint = new Paint();
//路径记录滑动屏幕的路径。
mPath = new Path();
mTextBound = new Rect();
mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.wallpaper);
//设置刮奖区样式
mBackPint = new Paint();
mBackPint.setColor(Color.RED);
mBackPint.setStrokeWidth(40);
mBackPint.setStyle(Paint.Style.FILL);
mBackPint.setTextScaleX(5f);
mBackPint.setColor(Color.RED);
mBackPint.setTextSize(30);
mBackPint.getTextBounds(mText, 0, mText.length(), mTextBound);
// 设置画笔
mOutterPaint = new Paint();
mOutterPaint.setColor(Color.RED);
mOutterPaint.setAntiAlias(true);
mOutterPaint.setDither(true);
mOutterPaint.setStyle(Paint.Style.STROKE);
mOutterPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
mOutterPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
// 设置画笔宽度
mOutterPaint.setStrokeWidth(20);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 初始化bitmap
if (mBitmap == null) {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
mCanvas.drawColor(Color.parseColor("#c0c0c0"));
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制奖项信息,这里用一个文本实现,也可以绘制一张图片
canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2,
getHeight() / 2 + mTextBound.height() / 2, mBackPint);
if (!isComplete) {
//如果刮奖涂层已被刮掉部分没有达到预设的比例,设置xfermode为DST_OUT,绘制用户刮的路径
mOutterPaint.setXfermode(mXfermode);
mCanvas.drawPath(mPath, mOutterPaint);
canvas.drawBitmap(mBitmap, 0, 0, null);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mCountThread != null && mCountThread.isAlive()) {
isComplete = true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
int x = (int) event.getX();
int y = (int) event.getY();
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastX = x;
mLastY = y;
mPath.moveTo(mLastX, mLastY);
break;
case MotionEvent.ACTION_MOVE:
int dx = Math.abs(x - mLastX);
int dy = Math.abs(y - mLastY);
if (dx > 3 || dy > 3) {
mPath.lineTo(x, y);
}
mLastX = x;
mLastY = y;
break;
case MotionEvent.ACTION_UP:
if (!mCountThread.isAlive()&&!isComplete) {
mCountThread.start();
}
break;
}
invalidate();
return true;
}
/**
* 计算刮奖涂层已被刮掉部分的比例
*/
class CountThread extends Thread {
private int[] mPixels;
@Override
public void run() {
while (!isComplete) {
int w = getWidth();
int h = getHeight();
float wipeArea = 0;
float totalArea = w * h;
Bitmap bitmap = mBitmap;
mPixels = new int[w * h];
/**
* 拿到所有的像素信息
*/
bitmap.getPixels(mPixels, 0, w, 0, 0, w, h);
/**
* 遍历统计擦除的区域
*/
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
int index = i + j * w;
if (mPixels[index] == 0) {
wipeArea++;
}
}
}
/**
* 根据所占百分比,进行一些操作
*/
if (wipeArea > 0 && totalArea > 0) {
int percent = (int) (wipeArea * 100 / totalArea);
if (percent > 70) {
isComplete = true;
postInvalidate();
}
}
}
}
}
}
上一篇: 从django的中间件直接返回请求的方法
推荐阅读
-
每日一学(二)刮刮卡效果实现
-
求教,有这么一个效果,当把鼠标放上去二维码慢慢的出来,鼠标离开二维码慢慢的下去,怎么去实现。_html/css_WEB-ITnose
-
AngularJS2中一种button切换效果的实现方法(二)
-
QT5每日一学(二)编写QT多窗口程序
-
求教,有这么一个效果,当把鼠标放上去二维码慢慢的出来,鼠标离开二维码慢慢的下去,怎么去实现。_html/css_WEB-ITnose
-
AngularJS2中一种button切换效果的实现方法(二)
-
jquery实现像栅栏一样左右滑出式二级菜单效果代码_jquery
-
jquery实现像栅栏一样左右滑出式二级菜单效果代码_jquery