序言:
很多哥们可能不喜欢买彩票,但是小时候肯定都刮过奖,5毛钱一次,今天我们要在android上面实现刮奖的控件。
功能:
奖的生成,刮奖,刮开面积的计算,分享到第三方平台。
效果图:
控件代码:
package com.example.xiangpica;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;
import com.example.xiangpica.bean.LotteryInfo;
import com.example.xiangpica.manage.LotteryManage;
public class MyView extends TextView {
private int widget, height;
private Context mContext;
private Paint mPaint;
private Canvas tempCanvas;
private Bitmap mBitmap;
private float x, y, ox, oy;
private Path mPath;
Handler mHandler;
MyThread mThread;
LotteryInfo info;
int messageCount;
int[] pixels;
int color = 0xFFD6D6D6;
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init(attrs);
}
/**
* 再一次抽奖
*/
public void againLotter() {
messageCount = 0;
info = LotteryManage.getRandomLottery();
tempCanvas.drawColor(color);
setText(info.getText());
}
public LotteryInfo getLotterInfo() {
return info;
}
private void init(AttributeSet attrs) {
// 获取控件大小值
TypedArray a = mContext.obtainStyledAttributes(attrs,
R.styleable.lotter);
widget = (int) a.getDimension(R.styleable.lotter_widget, 300);
height = (int) a.getDimension(R.styleable.lotter_height, 100);
a.recycle();
// 初始化路径
mPath = new Path();
// 初始化画笔
mPaint = new Paint();
mPaint.setColor(mContext.getResources().getColor(R.color.view_color));
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeWidth(50);//画笔宽度
// 初始化Bitmap并且锁定到临时画布上
mBitmap = Bitmap.createBitmap(widget, height, Bitmap.Config.ARGB_4444);
tempCanvas = new Canvas();
tempCanvas.setBitmap(mBitmap);
againLotter();
// 在字线程中创建Handler接收像素消息
mThread = new MyThread();
mThread.start();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 将处理过的bitmap画上去
canvas.drawBitmap(mBitmap, 0, 0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
touchDown(event);
break;
case MotionEvent.ACTION_MOVE:
touchMove(event);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
break;
}
return true;
}
/**
* 移动的时候
* @param event
*/
private void touchMove(MotionEvent event) {
x = event.getX();
y = event.getY();
// 二次贝塞尔,实现平滑曲线;oX, oY为操作点 x,y为终点
mPath.quadTo((x + ox) / 2, (y + oy) / 2, x, y);
tempCanvas.drawPath(mPath, mPaint);
ox = x;
oy = y;
invalidate();
computeScale();
}
/**
* 第一次按下来
*
* @param event
*/
private void touchDown(MotionEvent event) {
ox = x = event.getX();
oy = y = event.getY();
mPath.reset();
mPath.moveTo(ox, oy);
}
/**
* 计算百分比
*/
private void computeScale() {
Message msg = mHandler.obtainMessage(0);
msg.obj = ++messageCount;
mHandler.sendMessage(msg);
}
/**
* 异步线程,作用是创建handler接收处理消息。
* @author Administrator
*
*/
class MyThread extends Thread {
public MyThread() {
}
@Override
public void run() {
super.run();
/*
* 创建 handler前先初始化Looper.
*/
Looper.prepare();
mHandler = new Handler() {
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
// 只处理最后一次的百分比
if ((Integer) (msg.obj) != messageCount) {
return;
}
// 取出像素点
synchronized (mBitmap) {
if (pixels == null) {
pixels = new int[mBitmap.getWidth()
* mBitmap.getHeight()];
}
mBitmap.getPixels(pixels, 0, widget, 0, 0, widget,
height);
}
int sum = pixels.length;
int num = 0;
for (int i = 0; i < sum; i++) {
if (pixels[i] == 0) {
num++;
}
}
info.setScratchPercentage(num / (double) sum);
System.out.println("百分比:" + info.getScratchPercentage()
* 100);
}
};
/*
* 启动该线程的消息队列
*/
Looper.loop();
}
}
}
原理介绍:
1、刮彩票的实现,新建一张和控件一样大的Bitmap,然后根据此bitmap新建一个临时画布并设置此bitmap,这样子临时画布做的操作就会更改到这张bitmap上面,然后重写控件的ondraw方法每次都去draw这张bitmap即可。
2、刮开面积的计算,由于bitmap的表面区域随着刮的过程要不断计算太耗时,所以计算面积是异步进行的,再异步线程初始化handler,然后刮开部分有改变就通知handler去计算并发送计算的次数,handler计算的时候会判断是否是最后一次,如果不是就直接不算,这样的好处是刮开的过程中会不断的发送,只有最后一次发送的计算通知是有效的值,计算的原理就是拷贝出bitmap的像素值,然后遍历判断是0的像素点比例(为0的就是透明区域)。
3、奖品生成原理,采用随机数,0~1000,0~9是一等奖(概率1%)10~29是二等奖(概率2%)30~100是三等奖(概率7%)
4、分享控件的原理,博主之前的博客http://blog.csdn.net/panjidong_3/article/details/16943063有详细介绍,很方便直接拿来用。
下载:
刮刮乐:http://download.csdn.net/detail/panjidong_3/6703273