序言:
很多哥们可能不喜欢买彩票,但是小时候肯定都刮过奖,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