android刮奖控件,使用简单

序言:

很多哥们可能不喜欢买彩票,但是小时候肯定都刮过奖,5毛钱一次,今天我们要在android上面实现刮奖的控件。


功能:

奖的生成,刮奖,刮开面积的计算,分享到第三方平台。


效果图:

    


控件代码:

  1. package com.example.xiangpica;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Paint;  
  8. import android.graphics.Paint.Style;  
  9. import android.graphics.Path;  
  10. import android.graphics.PorterDuff.Mode;  
  11. import android.graphics.PorterDuffXfermode;  
  12. import android.os.Handler;  
  13. import android.os.Looper;  
  14. import android.os.Message;  
  15. import android.util.AttributeSet;  
  16. import android.view.MotionEvent;  
  17. import android.widget.TextView;  
  18.   
  19. import com.example.xiangpica.bean.LotteryInfo;  
  20. import com.example.xiangpica.manage.LotteryManage;  
  21.   
  22. public class MyView extends TextView {  
  23.   
  24.     private int widget, height;  
  25.   
  26.     private Context mContext;  
  27.     private Paint mPaint;  
  28.     private Canvas tempCanvas;  
  29.     private Bitmap mBitmap;  
  30.     private float x, y, ox, oy;  
  31.     private Path mPath;  
  32.     Handler mHandler;  
  33.     MyThread mThread;  
  34.   
  35.     LotteryInfo info;  
  36.     int messageCount;  
  37.   
  38.     int[] pixels;  
  39.       
  40.     int color = 0xFFD6D6D6;  
  41.   
  42.     public MyView(Context context, AttributeSet attrs) {  
  43.         super(context, attrs);  
  44.         mContext = context;  
  45.         init(attrs);  
  46.     }  
  47.   
  48.     /** 
  49.      * 再一次抽奖 
  50.      */  
  51.     public void againLotter() {  
  52.         messageCount = 0;  
  53.         info = LotteryManage.getRandomLottery();  
  54.         tempCanvas.drawColor(color);  
  55.         setText(info.getText());  
  56.     }  
  57.   
  58.     public LotteryInfo getLotterInfo() {  
  59.         return info;  
  60.     }  
  61.   
  62.     private void init(AttributeSet attrs) {  
  63.         // 获取控件大小值  
  64.         TypedArray a = mContext.obtainStyledAttributes(attrs,  
  65.                 R.styleable.lotter);  
  66.         widget = (int) a.getDimension(R.styleable.lotter_widget, 300);  
  67.         height = (int) a.getDimension(R.styleable.lotter_height, 100);  
  68.         a.recycle();  
  69.   
  70.         // 初始化路径  
  71.         mPath = new Path();  
  72.   
  73.         // 初始化画笔  
  74.         mPaint = new Paint();  
  75.         mPaint.setColor(mContext.getResources().getColor(R.color.view_color));  
  76.         mPaint.setAlpha(0);  
  77.         mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));  
  78.         mPaint.setAntiAlias(true);  
  79.         mPaint.setStyle(Style.STROKE);  
  80.         mPaint.setStrokeWidth(50);//画笔宽度  
  81.   
  82.         // 初始化Bitmap并且锁定到临时画布上  
  83.         mBitmap = Bitmap.createBitmap(widget, height, Bitmap.Config.ARGB_4444);  
  84.         tempCanvas = new Canvas();  
  85.         tempCanvas.setBitmap(mBitmap);  
  86.         againLotter();  
  87.   
  88.         // 在字线程中创建Handler接收像素消息  
  89.         mThread = new MyThread();  
  90.         mThread.start();  
  91.     }  
  92.   
  93.     @Override  
  94.     protected void onDraw(Canvas canvas) {  
  95.         super.onDraw(canvas);  
  96.         // 将处理过的bitmap画上去  
  97.         canvas.drawBitmap(mBitmap, 00null);  
  98.     }  
  99.   
  100.     @Override  
  101.     public boolean onTouchEvent(MotionEvent event) {  
  102.         int action = event.getAction();  
  103.         switch (action) {  
  104.         case MotionEvent.ACTION_DOWN:  
  105.             touchDown(event);  
  106.             break;  
  107.         case MotionEvent.ACTION_MOVE:  
  108.             touchMove(event);  
  109.             break;  
  110.         case MotionEvent.ACTION_CANCEL:  
  111.         case MotionEvent.ACTION_UP:  
  112.             break;  
  113.         }  
  114.         return true;  
  115.     }  
  116.   
  117.     /** 
  118.      *  移动的时候 
  119.      * @param event 
  120.      */  
  121.     private void touchMove(MotionEvent event) {  
  122.         x = event.getX();  
  123.         y = event.getY();  
  124.         // 二次贝塞尔,实现平滑曲线;oX, oY为操作点 x,y为终点   
  125.         mPath.quadTo((x + ox) / 2, (y + oy) / 2, x, y);  
  126.         tempCanvas.drawPath(mPath, mPaint);  
  127.         ox = x;  
  128.         oy = y;  
  129.         invalidate();  
  130.         computeScale();  
  131.     }  
  132.     /** 
  133.      * 第一次按下来 
  134.      *  
  135.      * @param event 
  136.      */  
  137.     private void touchDown(MotionEvent event) {  
  138.         ox = x = event.getX();  
  139.         oy = y = event.getY();  
  140.         mPath.reset();  
  141.         mPath.moveTo(ox, oy);  
  142.     }  
  143.     /** 
  144.      * 计算百分比 
  145.      */  
  146.     private void computeScale() {  
  147.         Message msg = mHandler.obtainMessage(0);  
  148.         msg.obj = ++messageCount;  
  149.         mHandler.sendMessage(msg);  
  150.     }  
  151.       
  152.     /** 
  153.      * 异步线程,作用是创建handler接收处理消息。 
  154.      * @author Administrator 
  155.      * 
  156.      */  
  157.     class MyThread extends Thread {  
  158.   
  159.         public MyThread() {  
  160.         }  
  161.   
  162.         @Override  
  163.         public void run() {  
  164.             super.run();  
  165.             /* 
  166.              * 创建 handler前先初始化Looper. 
  167.              */  
  168.             Looper.prepare();  
  169.   
  170.             mHandler = new Handler() {  
  171.                 @Override  
  172.                 public void dispatchMessage(Message msg) {  
  173.                     super.dispatchMessage(msg);  
  174.                     // 只处理最后一次的百分比  
  175.                     if ((Integer) (msg.obj) != messageCount) {  
  176.                         return;  
  177.                     }  
  178.                     // 取出像素点  
  179.                     synchronized (mBitmap) {  
  180.                         if (pixels == null) {  
  181.                             pixels = new int[mBitmap.getWidth()  
  182.                                     * mBitmap.getHeight()];  
  183.                         }  
  184.                         mBitmap.getPixels(pixels, 0, widget, 00, widget,  
  185.                                 height);  
  186.                     }  
  187.   
  188.                     int sum = pixels.length;  
  189.                     int num = 0;  
  190.                     for (int i = 0; i < sum; i++) {  
  191.                         if (pixels[i] == 0) {  
  192.                             num++;  
  193.                         }  
  194.                     }  
  195.                     info.setScratchPercentage(num / (double) sum);  
  196.                     System.out.println("百分比:" + info.getScratchPercentage()  
  197.                             * 100);  
  198.                 }  
  199.             };  
  200.             /* 
  201.              * 启动该线程的消息队列 
  202.              */  
  203.             Looper.loop();  
  204.         }  
  205.     }  
  206. }  


原理介绍:

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现刮奖效果,可以使用 Vue3 中的 `<canvas>` 标签来绘制刮奖区域和遮罩层,然后通过监听用户的鼠标或手指移动事件来擦除遮罩层,从而实现刮奖效果。 下面是一个简单的实现示例: ```vue <template> <div class="scratch-card"> <canvas ref="canvas" class="scratch-card__canvas"></canvas> </div> </template> <script> import { onMounted, onUnmounted, ref } from 'vue'; export default { name: 'ScratchCard', setup() { const canvasRef = ref(null); let ctx = null; let isDrawing = false; const handleStart = (e) => { isDrawing = true; ctx.beginPath(); ctx.moveTo(e.clientX, e.clientY); }; const handleMove = (e) => { if (isDrawing) { ctx.lineTo(e.clientX, e.clientY); ctx.stroke(); } }; const handleEnd = () => { isDrawing = false; }; onMounted(() => { const canvas = canvasRef.value; ctx = canvas.getContext('2d'); // 绘制刮奖区域 ctx.fillStyle = '#888'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 绘制遮罩层 ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, canvas.width, canvas.height); // 监听鼠标或手指移动事件 canvas.addEventListener('mousedown', handleStart); canvas.addEventListener('mousemove', handleMove); canvas.addEventListener('mouseup', handleEnd); canvas.addEventListener('touchstart', handleStart); canvas.addEventListener('touchmove', handleMove); canvas.addEventListener('touchend', handleEnd); }); onUnmounted(() => { const canvas = canvasRef.value; canvas.removeEventListener('mousedown', handleStart); canvas.removeEventListener('mousemove', handleMove); canvas.removeEventListener('mouseup', handleEnd); canvas.removeEventListener('touchstart', handleStart); canvas.removeEventListener('touchmove', handleMove); canvas.removeEventListener('touchend', handleEnd); }); return { canvasRef, }; }, }; </script> <style scoped> .scratch-card { position: relative; width: 300px; height: 200px; } .scratch-card__canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } </style> ``` 在这个示例中,我们使用 `<canvas>` 标签来创建一个刮奖区域,它的背景颜色是灰色的。然后,我们使用相同的大小和位置创建一个遮罩层,它的背景颜色是红色的。 在 `setup` 函数中,我们使用 `onMounted` 和 `onUnmounted` 生命周期钩子来监听鼠标或手指移动事件,并在事件处理程序中绘制用户的刮奖轨迹。我们还使用 `ref` 函数来创建一个引用,以便在模板中访问 `<canvas>` 元素。 最后,我们将组件的样式设置为相对定位,以便它的子元素(即 `<canvas>` 元素)可以使用绝对定位来覆盖它。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值