Android之九宫格抽奖及大转盘抽奖

本文介绍了一种基于Android平台的九宫格抽奖和大转盘抽奖的实现方法,包括自定义View实现抽奖界面,通过网络请求获取抽奖数据,以及动画效果的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:先来张效果图

二:实现步骤:

-------.九宫格抽奖是从后台服务器获取的数据,图片文字以及抽奖选中位置都是后台控制

一:九宫格抽奖

1九宫格抽奖工具类(里面包含网络请求,不需要的可去掉)

package pinbidarider.hsrd.com.pinbidarider.view;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import de.greenrobot.event.EventBus;
import okhttp3.Call;
import okhttp3.Response;
import pinbidarider.hsrd.com.pinbidarider.R;
import pinbidarider.hsrd.com.pinbidarider.application.MyApplication;
import pinbidarider.hsrd.com.pinbidarider.eventbus.EventBusIsCJ;
import pinbidarider.hsrd.com.pinbidarider.model.LuckDrawBean;
import pinbidarider.hsrd.com.pinbidarider.model.LuckyViewBean;
import pinbidarider.hsrd.com.pinbidarider.net.NetConst;
import pinbidarider.hsrd.com.pinbidarider.utils.ConstantUtil;
import pinbidarider.hsrd.com.pinbidarider.utils.JsonCllUtil;
import pinbidarider.hsrd.com.pinbidarider.utils.Okhttp3Utils;
import pinbidarider.hsrd.com.pinbidarider.utils.SpUtil;
import pinbidarider.hsrd.com.pinbidarider.utils.ToastUtils;

/**
 * 作者:CaoLiulang
 * ❤
 * Date:2021/1/11
 * ❤
 * 模块:
 */
public class LuckyView extends View {
    private Paint mPaint;
    private float mStrokeWidth = 5;
    private int mRepeatCount = 5; // 转的圈数
    private int mRectSize; // 矩形的宽和高(矩形为正方形)
    private boolean mShouldStartFlag;
    private boolean mShouldStartNextTurn = true; // 标记是否应该开启下一轮抽奖
    private int mStartLuckPosition = 0; // 开始抽奖的位置
    private int mCurrentPosition = -1; // 当前转圈所在的位置
    private LuckyViewBean bean;
    private OnLuckAnimationEndListener mLuckAnimationEndListener;
    /**
     * 可以通过对 mLuckNum 设置计算策略,来控制用户 中哪些奖 以及 中大奖 的概率
     */
    private int mLuckNum = 3; // 默认最终中奖位置

    private List<RectF> mRectFs; // 存储矩形的集合
    private int[] mItemColor = {Color.parseColor("#ffe9c6"), Color.parseColor("#ffe9c6")}; // 矩形的颜色
    private String[] mPrizeDescription = new String[9];//文字数组
    private float left;
    private float top;
    //本地图片
//    private int[] mLuckyPrizes = {R.mipmap.select_bg,R.mipmap.select_bg,R.mipmap.select_bg, R.mipmap.select_bg,R.mipmap.select_bg,R.mipmap.select_bg, R.mipmap.select_bg, R.mipmap.select_bg, R.mipmap.select_bg};
    //文字
//    private String[] mPrizeDescription = {"满20减1元券", "满10减1元券", "满30减2元券", "满5减1元券", "免单", "满300减40元券", "满100减10元券", "满500减50元券", "开始"};
    private Bitmap bitmap[] = new Bitmap[9];//图片数组
    private String message;

    public void setBitmap(Bitmap[] bitmap, String[] mPrizeDescription) {
        this.bitmap = bitmap;
        this.mPrizeDescription = mPrizeDescription;
        invalidate();
    }

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

    public LuckyView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LuckyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); // 抗锯齿
        mPaint.setStyle(Paint.Style.FILL);
        // mPaint.setStyle(Paint.Style.STROKE); // 设置样式为描边
        mPaint.setStrokeWidth(mStrokeWidth); // 设置描边的宽度

        mRectFs = new ArrayList<>();
    }

    public void setLuckAnimationEndListener(OnLuckAnimationEndListener luckAnimationEndListener) {
        mLuckAnimationEndListener = luckAnimationEndListener;
    }

    /**
     * 设置中奖位置
     *
     * @param luckNum
     */
    public void setLuckNum(int luckNum) {
        mLuckNum = luckNum;
    }

    //加载本地图片需要
//    public int[] getLuckyPrizes() {
//        return mLuckyPrizes;
//    }
//
//    public void setLuckyPrizes(int[] luckyPrizes) {
//        mLuckyPrizes = luckyPrizes;
//    }
    //设置图片,文字数据
    public void setData(List<String> lettersBeans) {
        invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 矩形的宽高
        mRectSize = (Math.min(w, h)) / 3;
        // 当控件大小改变的时候清空数据
        mRectFs.clear();
        initNineRect();
    }

    /**
     * 初始化 9 个矩形(正方形)的位置信息
     */
    private void initNineRect() {
        final float width = getWidth();

        // 加载前三个矩形
        for (int i = 0; i < 3; i++) {
            float left = i * mRectSize + 5;
            float right = (i + 1) * mRectSize;
            float top = 5;
            float bottom = mRectSize;
            RectF rectF = new RectF(left, top, right, bottom);
            mRectFs.add(rectF);
        }

        // 加载第 4 个矩形
        mRectFs.add(new RectF(width - mRectSize + 5, mRectSize + 5, width, 2 * mRectSize));

        // 加载第 5~7 个矩形
        for (int j = 3; j > 0; j--) {
            float left = width - (4 - j) * mRectSize + 5;
            float right = width - (3 - j) * mRectSize;
            float top = 2 * mRectSize + 5;
            float bottom = 3 * mRectSize;
            RectF rectF = new RectF(left, top, right, bottom);
            mRectFs.add(rectF);
        }

        // 加载第 8 个矩形
        mRectFs.add(new RectF(5, mRectSize + 5, mRectSize, 2 * mRectSize));

        // 加载中心第 9 个矩形
        mRectFs.add(new RectF(mRectSize + 5, mRectSize + 5, 2 * mRectSize, 2 * mRectSize));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //执行真正的绘制矩形操作
        drawNineRect(canvas);
        drawNineBitmaps(canvas);
//        // 填充奖品文字
        drawNineText(canvas);
    }

    /**
     * 在每个矩形中填充奖品图片
     * left:The position of the left side of the bitmap being drawn
     * top:The position of the top side of the bitmap being drawn
     */
    private void drawNineBitmaps(final Canvas canvas) {
        for (int i = 0; i < mRectFs.size(); i++) {
            RectF rectF = mRectFs.get(i);
            // 将图片设置在每个矩形中央
//            if (i == 8) {
//                left = rectF.left + mRectSize / 4;
//                top = rectF.top + mRectSize / 4;
//            } else {
//                left = rectF.left + mRectSize / 4;
//                top = rectF.top + mRectSize / 6;
//            }
            left = rectF.left + mRectSize / 4;
            top = rectF.top + mRectSize / 4;
            //加载本地图片
//            canvas.drawBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), mLuckyPrizes[i]), mRectSize / 2, mRectSize / 2, false), left, top, null);
            //加载网络图片
            if (null != bitmap[i]) {
                canvas.drawBitmap(Bitmap.createScaledBitmap(bitmap[i], mRectSize / 2, mRectSize / 2, false), left, top, null);
                EventBusIsCJ eventBusIsCJ = new EventBusIsCJ(1);
                EventBus.getDefault().post(eventBusIsCJ);
            }
        }
    }


    /**
     * 在每个矩形中央填充文字,代替抽奖图片
     * x:he x-coordinate of the origin of the text being drawn
     * y:The y-coordinate of the baseline of the text being drawn
     */
    private void drawNineText(Canvas canvas) {
        for (int i = 0; i < mRectFs.size(); i++) {
            RectF rectF = mRectFs.get(i);
            float x = rectF.left + mRectSize / 4; // 将文字设置在每个矩形中央
            float y = rectF.top + mRectSize - 40;
            mPaint.setColor(Color.parseColor("#B61320"));
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setTextSize(32); // unit px
            if (null != mPrizeDescription[i]) {
                if (i == mRectFs.size() - 1) {
                    canvas.drawText("", x, y, mPaint);
                } else {
                    canvas.drawText(mPrizeDescription[i], x, y, mPaint);
                }
            }
        }
    }

    /**
     * 执行真正的绘制矩形操作
     */
    private void drawNineRect(Canvas canvas) {
        for (int x = 0; x < mRectFs.size(); x++) {
            RectF rectF = mRectFs.get(x);
            if (x == 8) {//第九个背景颜色
                mPaint.setColor(Color.parseColor("#ffdf47"));
            } else {
                if (mCurrentPosition == x) {//选中颜色
                    mPaint.setColor(Color.parseColor("#f0c595"));
                } else {//正常颜色
                    mPaint.setColor(mItemColor[x % 2]); // 标记当前转盘经过的位置
                }
            }
            canvas.drawRect(rectF, mPaint);
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            mShouldStartFlag = mRectFs.get(8).contains(event.getX(), event.getY());
            return true;
        }
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (mShouldStartFlag) {
                if (mRectFs.get(8).contains(event.getX(), event.getY())) {
                    // mLuckAnimationEndListener.onClickLuck();
                    if (SpUtil.get(ConstantUtil.ISDRAW, "").equals("true")) {
                        rightDatelist();
                    } else {
                        ToastUtils.ToastCllShow("您的抽奖次数已用完");
                    }
                }
                mShouldStartFlag = false;
            }
        }
        return super.onTouchEvent(event);
    }

    /**
     * 抽奖计算 post 请求
     * (需要把参数放到request Body里面,并且在在header里面申明请求类型为“application/json”)
     */
    private void rightDatelist() {
        String url = NetConst.CJJS;
        System.out.println("====>>抽奖计算url:" + url);
        JSONObject jsonObjectTemp = new JSONObject();
        try {
            jsonObjectTemp.put("api_token", SpUtil.get(ConstantUtil.TokenApi, ""));
            jsonObjectTemp.put("appid", SpUtil.get(ConstantUtil.APPID, ""));
            jsonObjectTemp.put("type", "1");
            jsonObjectTemp.put("member_id", SpUtil.get(ConstantUtil.UserID, ""));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        String json = jsonObjectTemp.toString();
        System.out.println("抽奖计算post传json:" + json);
        //获取网络工具类实例
        Okhttp3Utils netUtils = Okhttp3Utils.getInstance();
        netUtils.doPostJson(url, json, new Okhttp3Utils.MyNetCall() {
            @Override
            public void success(Call call, Response response) throws IOException {
                try {
                    String star = response.body().string();
                    System.out.println("===>>抽奖计算成功:" + star);
                    /**把data下的数据转换成json对象**/
                    final JSONObject jDat = new JSONObject(star);
                    message = jDat.getString("message");
                    if (!jDat.getString("code").equals("0")) {
                        // 加载完数据之后,启动滑动
                        Message msg = new Message();
                        msg.what = 2;
                        handler1.sendMessage(msg);
                    }
                    if (jDat.getString("code").equals("0")) {
                        bean = JsonCllUtil.parseJsonToBean(jDat.getString("data"), LuckyViewBean.class);
                        // 加载完数据之后,启动滑动
                        Message msg = new Message();
                        msg.what = 1;
                        handler1.sendMessage(msg);
                    } else if (jDat.getString("code").equals("3")) {
                        MyApplication.ISDL();
                    } else {
                        // 加载完数据之后,启动滑动
                        Message msg = new Message();
                        msg.what = 2;
                        handler1.sendMessage(msg);
                    }

                } catch (Exception e) {
                }
            }

            @Override
            public void failed(Call call, IOException e) {
                // 加载完数据之后,启动滑动
                Message msg = new Message();
                msg.what = 2;
                handler1.sendMessage(msg);
            }
        });

    }


    @SuppressLint("HandlerLeak")
    Handler handler1 = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    if (SpUtil.get(ConstantUtil.ISDRAW, "").equals("true")) {//可抽奖
                        startAnim(); // 判断只有手指落下和抬起都在中间的矩形内时才开始执行动画抽奖
                        SpUtil.put(ConstantUtil.ISDRAW, bean.is_draw);
                    } else {
                        ToastUtils.ToastCllShow(message);
                    }
                    break;
                case 2:
                    ToastUtils.ToastCllShow(message);
                    break;

            }
        }
    };


    /**
     * 开始动画
     */
    private void startAnim() {
        if (!mShouldStartNextTurn) {
            return;
        }
        //本地设置随机数中间位置
//        Random random = new Random();
//        setLuckNum(random.nextInt(8));//开始抽奖的位置,转的圈数*8+中奖位置
        //接口回调中奖位置
        int cll = Integer.valueOf(bean.id).intValue();
        int cllc = cll - 1;
        setLuckNum(cllc);
        ValueAnimator animator = ValueAnimator.ofInt(mStartLuckPosition, mRepeatCount * 8 + mLuckNum)
                .setDuration(6000);

        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                final int position = (int) animation.getAnimatedValue();
                setCurrentPosition(position % 8);
                mShouldStartNextTurn = false;
            }
        });

        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mShouldStartNextTurn = true;
                mStartLuckPosition = mLuckNum;
                //最终选中的位置
                if (mLuckAnimationEndListener != null) {
                    mLuckAnimationEndListener.onLuckAnimationEnd(mCurrentPosition,
                            mPrizeDescription[mCurrentPosition]);
                }
            }
        });
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.start();
    }

    private void setCurrentPosition(int position) {
        mCurrentPosition = position;
        invalidate(); // 强制刷新,在 UI 线程回调 onDraw()
    }

    /**
     * 用于抽奖结果回调
     */
    public interface OnLuckAnimationEndListener {
        void onLuckAnimationEnd(int pos, String msg);
    }
}

2.activity请求到数据赋值给工具类

//声明变量
Bitmap bits[] = new Bitmap[9];//图片数组

 //在解析完数据后执行这局代码
new Thread(networkTask).start();

 /**
     * 网络操作相关的子线程
     */
    Runnable networkTask = new Runnable() {

        @Override
        public void run() {
            // TODO
            // 在这里进行 http request.网络请求相关操作
            for (int i = 0; i < bean.list.size(); i++) {
                final int finalI = i;
                BitmapUtil.returnBitmap(bean.list.get(i).thumb, new BitmapCallback() {
                    @Override
                    public void callback(Bitmap bitmap) {
                        if (null != bitmap) {
                            Message msg = new Message();
                            msg.arg1 = finalI;
                            msg.obj = bitmap;
                            handler.sendMessage(msg);
                        }
                    }
                });
            }

        }
    };

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            int code = msg.arg1;
            Bitmap bitmap = (Bitmap) msg.obj;
            // TODO
            // UI界面的更新等相关操作
            if (null != bitmap) {
                bits[code] = bitmap;
                if (code == bean.list.size() - 1) {
                    bits[8] = MyApplication.BMM();
                    String[] mPrizeDescription = {bean.list.get(0).name, bean.list.get(1).name, bean.list.get(2).name, bean.list.get(3).name, bean.list.get(4).name, bean.list.get(5).name, bean.list.get(6).name, bean.list.get(7).name, "开始"};
                    luckview.setBitmap(bits, mPrizeDescription);
                }
            }
        }
    };

3.xml布局

  <pinbidarider.hsrd.com.pinbidarider.view.LuckyView
                        android:id="@+id/luckview"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:layout_centerHorizontal="true"
                        android:layout_marginLeft="15dp"
                        android:layout_marginTop="85dp"
                        android:layout_marginRight="15dp"
                        android:layout_marginBottom="10dp" />

4.BitmapUtil工具类和BitmapCallback

package pinbidarider.hsrd.com.pinbidarider.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;


import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class BitmapUtil {
    /**
     * 根据图片的url路径获得Bitmap对象
     *
     * @param url
     * @return
     */
    public static Bitmap returnBitmap(String url, BitmapCallback callBack) {
        URL fileUrl = null;
        Bitmap bitmap = null;

        try {
            fileUrl = new URL(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }

        try {
            HttpURLConnection conn = (HttpURLConnection) fileUrl
                    .openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            bitmap = BitmapFactory.decodeStream(is);
            is.close();
            callBack.callback(bitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;

    }
}
package pinbidarider.hsrd.com.pinbidarider.utils;

import android.graphics.Bitmap;

public interface BitmapCallback {
    void callback(Bitmap bitmap);
}

二:大转盘

1.转盘抽奖的工具类:

package cll.com.myapplication;

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.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

/**
 *工具类
 */
public class BitWheelView extends SurfaceView implements Callback, Runnable {

    private SurfaceHolder mHolder;
    /**
     * 与SurfaceHolder绑定的Canvas
     */
    private Canvas mCanvas;
    /**
     * 用于绘制的线程
     */
    private Thread t;
    /**
     * 线程的控制开关
     */
    private boolean isRunning;

    /**
     * 抽奖的文字
     */
    private String[] mStrs = new String[]{"单反相机", "IPAD", "恭喜发财", "IPHONE",
            "妹子一只", "恭喜发财"};
    /**
     * 每个盘块的颜色
     */
    private int[] mColors = new int[]{0xFFFFC300, 0xFFF17E01, 0xFFFFC300,
            0xFFF17E01, 0xFFFFC300, 0xFFF17E01};
    /**
     * 与文字对应的图片
     */
    private int[] mImgs = new int[]{R.mipmap.danfan, R.mipmap.ipad,
            R.mipmap.f040, R.mipmap.iphone, R.mipmap.meizi,
            R.mipmap.f040};

    /**
     * 与文字对应图片的bitmap数组
     */
    private Bitmap[] mImgsBitmap;
    /**
     * 盘块的个数
     */
    private int mItemCount = 6;

    /**
     * 绘制盘块的范围
     */
    private RectF mRange = new RectF();
    /**
     * 圆的直径
     */
    private int mRadius;
    /**
     * 绘制盘快的画笔
     */
    private Paint mArcPaint;

    /**
     * 绘制文字的画笔
     */
    private Paint mTextPaint;

    /**
     * 滚动的速度
     */
    private double mSpeed;
    private volatile float mStartAngle = 0;
    /**
     * 是否点击了停止
     */
    private boolean isShouldEnd;

    /**
     * 控件的中心位置
     */
    private int mCenter;
    /**
     * 控件的padding,这里我们认为4个padding的值一致,以paddingleft为标准
     */
    private int mPadding;

    /**
     * 背景图的bitmap
     */
    private Bitmap mBgBitmap = BitmapFactory.decodeResource(getResources(),
            R.mipmap.bg2);
    /**
     * 文字的大小
     */
    private float mTextSize = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());

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

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

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

        // setZOrderOnTop(true);// 设置画布 背景透明
        // mHolder.setFormat(PixelFormat.TRANSLUCENT);

        setFocusable(true);
        setFocusableInTouchMode(true);
        this.setKeepScreenOn(true);

    }

    /**
     * 设置控件为正方形
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int width = Math.min(getMeasuredWidth(), getMeasuredHeight());
        // 获取圆形的直径
        mRadius = width - getPaddingLeft() - getPaddingRight();
        // padding值
        mPadding = getPaddingLeft();
        // 中心点
        mCenter = width / 2;
        setMeasuredDimension(width, width);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // 初始化绘制圆弧的画笔
        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setDither(true);
        // 初始化绘制文字的画笔
        mTextPaint = new Paint();
        mTextPaint.setColor(0xFFffffff);
        mTextPaint.setTextSize(mTextSize);
        // 圆弧的绘制范围
        mRange = new RectF(getPaddingLeft(), getPaddingLeft(), mRadius
                + getPaddingLeft(), mRadius + getPaddingLeft());

        // 初始化图片
        mImgsBitmap = new Bitmap[mItemCount];
        for (int i = 0; i < mItemCount; i++) {
            mImgsBitmap[i] = BitmapFactory.decodeResource(getResources(),
                    mImgs[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() {
        // 不断的进行draw
        while (isRunning) {
            long start = System.currentTimeMillis();
            draw();
            long end = System.currentTimeMillis();
            try {
                if (end - start < 50) {
                    Thread.sleep(50 - (end - start));
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    }

    private void draw() {
        try {
            // 获得canvas
            mCanvas = mHolder.lockCanvas();
            if (mCanvas != null) {
                // 绘制背景图
                drawBg();

                /**
                 * 绘制每个块块,每个块块上的文本,每个块块上的图片
                 */
                float tmpAngle = mStartAngle;
                float sweepAngle = (float) (360 / mItemCount);
                for (int i = 0; i < mItemCount; i++) {
                    // 绘制快快
                    mArcPaint.setColor(mColors[i]);
//             mArcPaint.setStyle(Style.STROKE);
                    mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true,
                            mArcPaint);
                    // 绘制文本
                    drawText(tmpAngle, sweepAngle, mStrs[i]);
                    // 绘制Icon
                    drawIcon(tmpAngle, i);

                    tmpAngle += sweepAngle;
                }

                // 如果mSpeed不等于0,则相当于在滚动
                mStartAngle += mSpeed;

                // 点击停止时,设置mSpeed为递减,为0值转盘停止
                if (isShouldEnd) {
                    mSpeed -= 1;
                }
                if (mSpeed <= 0) {
                    mSpeed = 0;
                    isShouldEnd = false;
                }
                // 根据当前旋转的mStartAngle计算当前滚动到的区域
                calInExactArea(mStartAngle);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (mCanvas != null)
                mHolder.unlockCanvasAndPost(mCanvas);
        }

    }

    /**
     * 根据当前旋转的mStartAngle计算当前滚动到的区域 绘制背景,不重要,完全为了美观
     */
    private void drawBg() {
        mCanvas.drawColor(0xFFFFFFFF);
        mCanvas.drawBitmap(mBgBitmap, null, new Rect(mPadding / 2,
                mPadding / 2, getMeasuredWidth() - mPadding / 2,
                getMeasuredWidth() - mPadding / 2), null);
    }

    /**
     * 根据当前旋转的mStartAngle计算当前滚动到的区域
     *
     * @param startAngle
     */
    public void calInExactArea(float startAngle) {
        // 让指针从水平向右开始计算
        float rotate = startAngle + 90;
        rotate %= 360.0;
        for (int i = 0; i < mItemCount; i++) {
            // 每个的中奖范围
            float from = 360 - (i + 1) * (360 / mItemCount);
            float to = from + 360 - (i) * (360 / mItemCount);

            if ((rotate > from) && (rotate < to)) {
                Log.d("TAG", mStrs[i]);
                return;
            }
        }
    }

    /**
     * 绘制图片
     *
     * @param startAngle
     * @param
     * @param i
     */
    private void drawIcon(float startAngle, int i) {
        // 设置图片的宽度为直径的1/8
        int imgWidth = mRadius / 8;

        float angle = (float) ((30 + startAngle) * (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(mImgsBitmap[i], null, rect, null);

    }

    /**
     * 绘制文本
     *
     * @param
     * @param startAngle
     * @param sweepAngle
     * @param string
     */
    private void drawText(float startAngle, float sweepAngle, String string) {
        Path path = new Path();
        path.addArc(mRange, startAngle, sweepAngle);
        float textWidth = mTextPaint.measureText(string);
        // 利用水平偏移让文字居中
        float hOffset = (float) (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);// 水平偏移
        float vOffset = mRadius / 2 / 6;// 垂直偏移
        mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);
    }

    /**
     * 点击开始旋转
     *
     * @param luckyIndex
     */
    public void luckyStart(int luckyIndex) {
        // 每项角度大小
        float angle = (float) (360 / mItemCount);
        // 中奖角度范围(因为指针向上,所以水平第一项旋转到指针指向,需要旋转210-270;)
        float from = 270 - (luckyIndex + 1) * angle;
        float to = from + angle;
        // 停下来时旋转的距离
        float targetFrom = 4 * 360 + from;
        /**
         * <pre>
         *  (v1 + 0) * (v1+1) / 2 = target ;
         *  v1*v1 + v1 - 2target = 0 ;
         *  v1=-1+(1*1 + 8 *1 * target)/2;
         * </pre>
         */
        float v1 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetFrom) - 1) / 2;
        float targetTo = 4 * 360 + to;
        float v2 = (float) (Math.sqrt(1 * 1 + 8 * 1 * targetTo) - 1) / 2;

        mSpeed = (float) (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;
    }

}

------------------就那么简单,有不懂得自己下demo看,不喜勿喷(九宫格是后面改良过的没有demo,链接上的demo是之前的九宫格和大转盘)、

------------------demo地址:点击打开链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶已初秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值