Android实现抽奖转盘

慕课网视频

 

今天学习了以下抽奖转盘的实现

 

首先学习了以下 SurfaceView 的一般使用方法

下面的代码是 写 SurfaceView 的一个模板

package com.negro.myluckypan;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by Administrator on 2015/8/4 0004.
 */
public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder mHolder ;
    private Canvas mCanvas ;

    private Thread mThread ;

    private boolean isRunning ;

    public SurfaceViewTempalte(Context context) {
        this(context, null);
    }

    public SurfaceViewTempalte(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHolder = getHolder() ;
        mHolder.addCallback(this);

        // 可获取焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        // 设置常亮
        setKeepScreenOn(true);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning = true ;
        mThread = new Thread(this) ;
        mThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false ;
    }

    @Override
    public void run() {
        while(isRunning) {
            draw() ;
        }
    }

    private void draw() {
        try {
            mCanvas = mHolder.lockCanvas() ;

            if(mCanvas == null) return ;

            // TODO draw something



        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }
}

 

想绘制什么东西,就用 canvas 在 draw 方法里面进行绘制

 

package com.negro.myluckypan;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

/**
 * Created by Administrator on 2015/8/4 0004.
 */
public class LuckyPan extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private SurfaceHolder mHolder ;
    private Canvas mCanvas ;

    private Thread mThread ;

    private boolean isRunning ;

    // 盘快的奖项
    private String[] mStrs = new String[] {
            "单反相机",
            "IPAD",
            "恭喜发财",
            "IPHONE",
            "服装一套",
            "恭喜发财"
    };

    // 盘快的图片
    private int[] mImgs = new int[] {
            R.drawable.danfan,
            R.drawable.ipad,
            R.drawable.f015,
            R.drawable.iphone,
            R.drawable.meizi,
            R.drawable.f040,
    } ;

    // 与图片对应的 bitmap 数组
    private Bitmap[] mImgBitmap ;

    // 盘快的颜色
    private int[] mColors = new int[] {
            0xffffc300,
            0xfff17e01,
            0xffffc300,
            0xfff17e01,
            0xffffc300,
            0xfff17e01
    } ;

    private int mItemCount = 6 ;

    /// 整个盘快的范围
    private RectF mRange = new RectF();

    // 整个盘快的直径
    private int mRadius ;

    // 绘制盘快的画笔
    private Paint mArcPaint ;

    // 绘制文本的画笔
    private Paint mTextPaint ;

    // 盘快滚动的速度
    private double mSpeed = 0 ;

    // 初始的角度   线程间的可见性
    private volatile float mStartAngle = 0 ;

    // 判断是否点击了停止按钮  避免用户一直点
    private boolean isShouldEnd ;

    // 转盘的中心位置
    private int mCenter ;

    // 这里我们以 paddingleft 为准
    private int mPadding ;

    // 背景图片
    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg2) ;

    // 字体大小
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics()) ;

    public LuckyPan(Context context) {
        this(context, null);
    }

    public LuckyPan(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHolder = getHolder() ;
        mHolder.addCallback(this);

        // 可获取焦点
        setFocusable(true);
        setFocusableInTouchMode(true);
        // 设置常亮
        setKeepScreenOn(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = Math.min(getMeasuredWidth(), getMeasuredHeight()) ;

        mPadding = getPaddingLeft() ;

        // 直径
        mRadius = width - mPadding * 2 ;

        // 中心点
        mCenter = width / 2 ;

        setMeasuredDimension(width, width);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {

        // 初始化绘制盘快的画笔
        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setDither(true);
        // 初始化绘制文本的画笔
        mTextPaint = new TextPaint();
        mTextPaint.setColor(0xffffffff);
        mTextPaint.setTextSize(mTextSize);

        // 初始化盘快绘制的范围
        mRange = new RectF(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius);

        // 初始化图片
        mImgBitmap = new Bitmap[mItemCount];

        for(int i = 0; i < mItemCount; i ++) {
            mImgBitmap[i] = BitmapFactory.decodeResource(getResources(), mImgs[i]) ;
        }

        isRunning = true ;
        mThread = new Thread(this) ;
        mThread.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning = false ;
    }

    @Override
    public void run() {
        while(isRunning) {
            // 1秒绘制20次就可以了
            long start = System.currentTimeMillis() ;
            draw() ;
            long end = System.currentTimeMillis() ;
            if(end - start < 50) {
                try {
                    Thread.sleep(50 - (end - start));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void draw() {
        try {
            mCanvas = mHolder.lockCanvas() ;

            if(mCanvas == null) return ;

            // TODO draw something

            ///  绘制  /
            drawBg() ;

            float tmpAngle = mStartAngle ;
            float sweepAngle = 360 / mItemCount ;
            for(int i = 0; i < mItemCount; i ++) {
                mArcPaint.setColor(mColors[i]);
                // 绘制盘快
                mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mArcPaint);

                // 绘制文本
                drawText(tmpAngle, sweepAngle, mStrs[i]) ;

                // 绘制图片
                drawIcon(tmpAngle, mImgBitmap[i]) ;

                tmpAngle += sweepAngle ;
            }

            mStartAngle += mSpeed ;

            // 如果点击了 停止按钮
            if(isShouldEnd) {
                mSpeed -= 1 ;
            }
            if(mSpeed <= 0) {
                mSpeed = 0 ;
                isShouldEnd = false ;
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(mCanvas != null) {
                mHolder.unlockCanvasAndPost(mCanvas);
            }
        }
    }

    // 绘制 icon
    private void drawIcon(float tmpAngle, Bitmap bitmap) {
        // 设置图片的宽度,为 直径的 二分之一
        int imgWidth = mRadius / 8 ;

        float angle = (float) ((tmpAngle + 360 / mItemCount / 2) * Math.PI / 180);

        // 确定图片中心点的坐标
        int x = (int) (mCenter + mRadius / 2 / 2 * Math.cos(angle));
        int y = (int) (mCenter + mRadius / 2 / 2 * Math.sin(angle));

        Rect rect = new Rect(x - imgWidth / 2, y - imgWidth / 2, x + imgWidth / 2, y + imgWidth / 2);

        mCanvas.drawBitmap(bitmap, null, rect, null);

    }

    // 绘制每个盘快的文本
    private void drawText(float tmpAngle, float sweepAngle, String mStr) {
        Path path = new Path();
        path.addArc(mRange, tmpAngle, sweepAngle);

        // 利用水平偏移量,让文字居中
        float textWidth = mTextPaint.measureText(mStr) ;
        int hOffset = (int) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);

        // 垂直偏移量
        int vOffset = mRadius / 2 / 6 ;

        mCanvas.drawTextOnPath(mStr, path, hOffset, vOffset, mTextPaint);
    }

    // 绘制背景
    private void drawBg() {
        mCanvas.drawColor(0xffffffff);
        mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), null);
    }

    // 点击 启动旋转
    public void luckyStart(int index) {

        // 计算每一项的角度
        float angle = 360 / mItemCount ;

        // 计算每一项的中奖范围(当前index)
        // 1 ->  150 ~ 210
        // 0 ->  210 ~ 270

        float from = 270 - (index + 1) * angle ;
        float end = from + angle ;

        // 设置停下来需要旋转的距离
        float targetFrom = 4 * 360 + from ;
        float targetEnd = 4 * 360 + end ;

        /**
         * 速度是递减的,每个周期 减一
         * v1   v1 - 1   v1 - 2  .....   0
         * v1 * (v1 + 1) / 2 == targetFrom
         * 可以计算出 v1 = (-1 + Math.sqrt(1 + 8 * targetFrom)) / 2
         */
        float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2);
        float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2);

        mSpeed = v1 + Math.random() * (v2 - v1) ;

        isShouldEnd = false ;
    }

    // 点击 停止旋转
    public void luckyEnd() {
        mStartAngle = 0 ;
        isShouldEnd = true ;
    }

    // 转盘是否在旋转
    public boolean isStart() {
        return mSpeed != 0 ;
    }

    // 判断 转盘是否停止旋转
    public boolean isShouldEnd() {
        return isShouldEnd ;
    }
}

 

在 MainActivity 里面

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLuckyPan = (LuckyPan) findViewById(R.id.id_luckypan);
        mStartBtn = (ImageView) findViewById(R.id.id_start_btn);

        mStartBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(!mLuckyPan.isStart()) {
                    mLuckyPan.luckyStart(1);
                    mStartBtn.setImageResource(R.drawable.stop);
                } else {
                    if(!mLuckyPan.isShouldEnd()) {
                        mLuckyPan.luckyEnd();
                        mStartBtn.setImageResource(R.drawable.start);
                    }
                }
            }
        });
    }

 

源代码下载

 

转载于:https://www.cnblogs.com/niulinguo/p/4701963.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值