序言:
很多哥们可能不喜欢买彩票,但是小时候肯定都刮过奖,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有详细介绍,很方便直接拿来用。
下载: