Android实现抽奖转盘

一、SurfaceView认识及的应用的思路

  • SurfaceView继承自(extends)View,View是在UI线程中进行绘制;
  • 而SurfaceView是在一个子线程中对自己进行绘制,优势:避免造成UI线程阻塞;
  • SurfaceView中包含一个专门用于绘制的Surface,Surface中包含一个Canvas;
  • 获得Canvas:可以从SurfaceView中方法的getHolder()获得SurfaceHolder,从holder获得Canvas;
  • holder还管理着SurfaceView的生命周期

         ①surfaceCreated()创建子线程,子线程的run()方法中开启SurfaceView的绘制。

         ②surfaceChanged()

           surfaceDestoryed()中关闭子线程。

二、SurfaceView的一般写法

 1 package com.example.luckypan;
 2 
 3 import android.content.Context;
 4 import android.graphics.Canvas;
 5 import android.util.AttributeSet;
 6 import android.view.SurfaceHolder;
 7 import android.view.SurfaceHolder.Callback;
 8 import android.view.SurfaceView;
 9 
10 public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable {
11 
12     private SurfaceHolder mHolder;
13     private Canvas mCanvas;
14     /**
15      * 用于绘制线程
16      */
17     private Thread thread;
18     /**
19      * 线程的控制开关
20      */
21     private boolean isRunning;
22     public SurfaceViewTemplate(Context context) {
23         this(context, null);
24     }
25     public SurfaceViewTemplate(Context context, AttributeSet attrs) {
26         super(context, attrs);
27         mHolder=getHolder();
28         mHolder.addCallback(this);
29         //可获得焦点
30         setFocusable(true);
31         setFocusableInTouchMode(true);
32         //设置常量
33         setKeepScreenOn(true);
34     }
35     public void surfaceCreated(SurfaceHolder holder) {
36         isRunning=true;
37         thread=new Thread(this);
38         thread.start();
39         
40     }
41     public void surfaceChanged(SurfaceHolder holder, int format, int width,
42             int height) {
43         // TODO Auto-generated method stub
44         
45     }
46     public void surfaceDestroyed(SurfaceHolder holder) {
47         isRunning=false;
48         
49     }
50     public void run() {
51         //不断进行绘制
52         while (isRunning)
53         {
54             draw();
55         }
56     }
57     private void draw() {
58         try {
59             mCanvas=mHolder.lockCanvas();
60             if (mCanvas!=null) {
61                 //
62             }
63         }
64         catch (Exception e) {
65         
66         }
67         finally
68         {
69             if (mCanvas!=null) {
70                 mHolder.unlockCanvasAndPost(mCanvas);
71             }
72         }
73     }
74 
75 
76 }
SurfaceViewTemplate

三、代码编写

  • 绘制抽奖转盘的盘快
  1.         绘制背景:drawBg(), Canvas的两个方法:drawColor(color the color to draw onto the canvas),这里我设置背景色为白色0xFFFFFFFF、drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint),这个bitmap是背景图片,背景是一个矩形new Rect(),其他参数设置为null。
    1. 1 private void drawBg() {
      2         mCanvas.drawColor(0xFFFFFFFF);
      3         mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding/2, mPadding/2, getMeasuredWidth()-mPadding/2, getMeasuredHeight()-mPadding/2), null);
      4     }
      drawBg
  2. 绘制盘快:
1 //绘制盘快
2                 float tmpAngle=mStartAngle;
3                 float sweepAngle=360/mItemCount;
4                 for (int i = 0; i < mItemCount; i++) {
5                     mArcPaint.setColor(mColor[i]);
6                     //绘制盘快
7                     mCanvas.drawArc(mRange, tmpAngle, sweepAngle,true, mArcPaint);
View Code
  • 绘制抽奖转盘的奖项文字
 1 /**
 2      * 绘制每个盘快的文本
 3      * @param tmpAngle
 4      * @param sweepAngle
 5      * @param string
 6      */
 7     private void drawText(float tmpAngle, float sweepAngle, String string) {
 8         Path path=new Path();
 9         path.addArc(mRange, tmpAngle, sweepAngle);
10         //利用水平偏移量让文字居中
11         float textWidth=mTextPaint.measureText(string);
12         int hOffset=(int) (mRadius*Math.PI/mItemCount/2-textWidth/2);
13         int vOffset=mRadius/2/6;//垂直偏移量
14         mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);
15     }
drawText
  • 绘制抽奖转盘的图片
 1 /**
 2      * 绘制图片
 3      * @param tmpAngle
 4      * @param bitmap
 5      */
 6     private void drawIcon(float tmpAngle, Bitmap bitmap) {
 7         //设置图片的宽度为直径的1/8
 8         int imgWidth=mRadius/8;
 9         float angle=(float) ((tmpAngle+360/mItemCount/2)*Math.PI/180);
10         int x=(int) (mCenter+mRadius/2/2*Math.cos(angle));
11         int y=(int) (mCenter+mRadius/2/2*Math.sin(angle));
12         //确定图片位置
13         Rect rect=new Rect(x-imgWidth/2, y-imgWidth/2, x+imgWidth/2, y+imgWidth/2);
14         mCanvas.drawBitmap(bitmap, null, rect,null);
15     }
drawIcon
  • 转盘滚动及设置停止的指向
 1 private void draw() {
 2         try {
 3             mCanvas=mHolder.lockCanvas();
 4             if (mCanvas!=null) {
 5                 //绘制背景
 6                 drawBg();
 7                 //绘制盘快
 8                 float tmpAngle=mStartAngle;
 9                 float sweepAngle=360/mItemCount;
10                 for (int i = 0; i < mItemCount; i++) {
11                     mArcPaint.setColor(mColor[i]);
12                     //绘制盘快
13                     mCanvas.drawArc(mRange, tmpAngle, sweepAngle,true, mArcPaint);
14                     //绘制文本
15                     drawText(tmpAngle,sweepAngle,mStrings[i]);
16                     //绘制图片
17                     drawIcon(tmpAngle,mImagBitmaps[i]);
18                     tmpAngle+=sweepAngle;
19                 }
20                 mStartAngle+=mSpeed;
21                 //判断是否点击停止按钮
22                 if (isShouldEnd) {
23                     mSpeed-=1;
24                 }
25                 if (mSpeed<=0)
26                 {
27                     mSpeed=0;
28                     isShouldEnd=false;
29                 }
30             }
31         }
32         catch (Exception e) {
33         
34         }
35         finally
36         {
37             if (mCanvas!=null) {
38                 mHolder.unlockCanvasAndPost(mCanvas);
39             }
40         }
41     }
draw

四、抽奖转盘的秘密

 1 /**
 2      * 电机启动旋转
 3      * 控制指定盘快停止范围
 4      * @param index
 5      */
 6     public void luckyStart(int index)
 7     {
 8         //计算每一项的角度
 9         float angle=360/mItemCount;
10         //计算每一项的中奖范围
11         //1->150~210
12         //0->210~270
13         float from=270-(index+1)*angle;
14         float end=from+angle;
15     //        设置停下来需要旋转的距离
16         float targetFrom=4*360+from;
17         float targetEnd=4*360+end;
18         /**
19          * <pre>
20          * v1->0 且每次-1
21          * (v1+0)*(v1+1)/2=targetFrom 等差数列求和公式;
22          * v1*v1+v1-2*targetFrom=0;
23          * v1=(-1+Math.sqrt(1+8*targetFrom))/2 一元二次方程求根公式
24          * </pre>
25          */
26         float v1=(float) ((-1+Math.sqrt(1+8*targetFrom))/2);
27         float v2=(float) ((-1+Math.sqrt(1+8*targetEnd))/2);
28         mSpeed=v1+Math.random()*(v2-v1);
29 //        mSpeed=v2;
30         isShouldEnd=false;
31     }
luckyStart
posted @ 2015-10-30 15:39  爱啦啦  阅读(3475)  评论(10编辑  收藏  举报