SurfaceView 实现 转盘抽奖

本文主要实现的是一个转盘游戏,并且可以调整中奖概率。其实这个主要的实现方式就是继承SurfaceView来实现试图绘制。

话不多说,直接上源码:

MySuraceView.java(主要用与绘制转盘界面和转盘逻辑)

package com.jt.study;

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

/**
 * Created by JT on  2015/7/28.
 */
public class SurfaceViewTempalte extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private SurfaceHolder mHolder;
    private Canvas mCanvas;

    /**
     *
     */
    private Thread t;
    /**
     * 线程的控制开关
     */
    private boolean isRunning;

    private int mPadding;
    private int mRaduis;
    private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
    private int mCenter;
    private Paint mArcPaint;
    private Paint bgArcPaint;
    private Paint mTextPaint;
    private int mItemCount = 6;
    private int[] smallImg = new int[]{R.drawable.ic_smile, R.drawable.ic_phone, R.drawable.ic_zhi, R.drawable.ic_smile, R.drawable.ic_danfan, R.drawable.ic_zhi};
    private String[] strings = new String[]{"谢谢惠顾", "手机", "餐巾纸", "谢谢惠顾", "单反", "餐巾纸"};
    private Bitmap[] mImageBitmap;
    private RectF mRectf = new RectF();
    private int[] colors = new int[]{0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699, 0xff33FF00, 0xffCC6699};
    private volatile float mStartAngle = 0;


    private float mSpeed;
    private boolean isShouleEnd;

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

    public SurfaceViewTempalte(Context context, AttributeSet attrs) {
        super(context, attrs);
        mHolder = getHolder();
        mHolder.addCallback(this);

        setFocusable(true);
        setFocusableInTouchMode(true);
        //设置常量
        setKeepScreenOn(true);
    }

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


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.d(TAG, "surfaceCreated");
        //初始化盘快的画笔
        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setDither(true);
        //初始化盘块背景图片
        bgArcPaint = new Paint();
        bgArcPaint.setAntiAlias(true);
        bgArcPaint.setDither(true);
        bgArcPaint.setColor(Color.RED);
        //初始化绘制盘块的文本画笔
        mTextPaint = new Paint();
        mTextPaint.setColor(0xffffffff);
        mTextPaint.setTextSize(mTextSize);

        //初始化盘块的绘制范围
        mRectf = new RectF(mPadding, mPadding, mPadding + mRaduis, mPadding + mRaduis);

        //初始化图片
        mImageBitmap = new Bitmap[mItemCount];
        for (int i = 0; i < mImageBitmap.length; i++) {
            mImageBitmap[i] = BitmapFactory.decodeResource(getResources(), smallImg[i]);
        }
        isRunning = true;
        t = new Thread(this);
        t.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) {
            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) {
//                mCanvas.drawArc(mRectf);
                drawBg();
                float tmpAngle = mStartAngle;
                float sweepAngle = 360 / mItemCount;
                for (int i = 0; i < mItemCount; i++) {
                    mArcPaint.setColor(colors[i]);
                    mCanvas.drawArc(mRectf, tmpAngle, sweepAngle, true, mArcPaint);
                    drawText(tmpAngle, sweepAngle, strings[i]);
                    drawIcon(tmpAngle, BitmapFactory.decodeResource(getResources(), smallImg[i]));
                    tmpAngle = sweepAngle + tmpAngle;
                }
                mStartAngle += mSpeed;
                Log.d(TAG, "mstartAngle " + mStartAngle);
                //判断是否点击停止按钮
                if (isShouleEnd) {
                    mSpeed -= 1;
                    drawStart("结束");
                } else {
                    drawStart("开始");
                }
                if (mSpeed <= 0) {
                    mSpeed = 0;
                    isShouleEnd = false;
                }
                drawArrow();
            }

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


    /**
     * @param tmpAngle
     * @param sweepAngle
     * @param text       绘制模块文字
     */
    private void drawText(float tmpAngle, float sweepAngle, String text) {
        Path path = new Path();
        path.addArc(mRectf, tmpAngle, sweepAngle);
        int textWidth = (int) mTextPaint.measureText(text);
        int hOffset = (int) (mRaduis * Math.PI / mItemCount / 2 - textWidth / 2);
        mCanvas.drawTextOnPath(text, path, hOffset, mRaduis / 9, mTextPaint);
    }

    /**
     * @param tmpAngle 偏转角度
     * @param bitmap   绘制每个模块的图片
     */
    private void drawIcon(float tmpAngle, Bitmap bitmap) {
        int imgWidth = mRaduis / 8;
        float angle = (float) ((tmpAngle + 360 / mItemCount / 2) * Math.PI / 180);
        int x = (int) (mCenter + mRaduis / 4 * Math.cos(angle));
        int y = (int) (mCenter + mRaduis / 4 * 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 drawBg() {
        Log.d(TAG, "drawBg");
        mCanvas.drawColor(Color.WHITE);
        mCanvas.drawArc(new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), 0, 360, true, bgArcPaint);
//        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_circle), null, new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), null);
    }

    /**
     * 绘制箭头
     */
    private void drawArrow() {
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        mCanvas.drawLine(mCenter, mCenter, mCenter, mCenter - mRaduis / 4, paint);
        Path path = new Path();
        paint.setStyle(Paint.Style.STROKE);
        path.moveTo(mCenter - 10, mCenter - mRaduis / 5);
        path.lineTo(mCenter, mCenter - mRaduis / 4);
        path.lineTo(mCenter + 10, mCenter - mRaduis / 5);

        mCanvas.drawPath(path, paint);
    }

    /**
     * @param text 绘制中间开始按钮
     */
    public void drawStart(String text) {
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setAntiAlias(true);
        mCanvas.drawCircle(mCenter, mCenter, 40, paint);
        paint.reset();
        paint.setColor(Color.WHITE);
        paint.setTextSize(mTextSize);
        paint.setAntiAlias(true);
        mCanvas.drawText(text, mCenter - paint.measureText(text) / 2, mCenter + paint.measureText(text) / 5, paint);
    }

    private final static String TAG = "SurfaceViewTempalate";

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Log.d(TAG, "onMeasure");
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRaduis = width - getPaddingLeft() * 2;//直径
        mCenter = width / 2;//中心点
        mPadding = getPaddingLeft();
        setMeasuredDimension(width, width);
    }

    /**
     * 开始转盘 index是表示你想抽中的那个选项的位置
     */
    public void luckStart(int index) {
        int angle = 360 / mItemCount;//每一项的角度
        //计算每一项中奖范围(当前index) 如果index=1对应的是150~210度
        float from = 270 - (index + 1) * angle;//最小角度
        float end = from + angle;//最大角度
        float targetFrom = 4 * 360 + from;//点击停止之后,需要转的最小角度
        float targetEnd = 4 * 360 + end;//点击停止之后,需要转的最大角度
        float v1 = (float) ((-1 + Math.sqrt(1 + 8 * targetFrom)) / 2);//最小速度
        float v2 = (float) ((-1 + Math.sqrt(1 + 8 * targetEnd)) / 2);//最大速度

        mSpeed = (float) (v1 + Math.random() * (v2 - v1));//在这两者速度之间都能抽中该选项
        isShouleEnd = false;
    }

    /**
     * 停止转盘
     */
    public void luckEnd() {
        mStartAngle = 0;
        isShouleEnd = true;
    }

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

    /**
     * @return 转盘是否被点击成了停止
     */
    public boolean isShouleEnd() {
        return isShouleEnd;
    }
}
MainActivity.java 用于控制开始与结束

package com.jt.study;

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;


public class MainActivity extends Activity {
    private SurfaceViewTempalte surfaceViewTempalte;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        surfaceViewTempalte = (SurfaceViewTempalte) findViewById(R.id.surfice);
        surfaceViewTempalte.setOnClickListener(new View.OnClickListener() {
                                                   @Override
                                                   public void onClick(View v) {
                                                       if (!surfaceViewTempalte.isStart()) {
                                                           surfaceViewTempalte.luckStart(0);
                                                       } else {
                                                           if (!surfaceViewTempalte.isShouleEnd()) {
                                                               surfaceViewTempalte.luckEnd();
                                                           }
                                                       }
                                                   }
                                               }
        );


    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
本文主要的难点和重点在于canvas的使用和角度旋转的逻辑,代码我已经加了注释,如果有不懂的可以留言和评论。谢谢!


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值