一:先来张效果图

二:实现步骤:

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

一:九宫格抽奖

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();}@Overrideprotected 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));}@Overrideprotected 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 pxif (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")@Overridepublic 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() {@Overridepublic 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) {}}@Overridepublic void failed(Call call, IOException e) {// 加载完数据之后,启动滑动Message msg = new Message();msg.what = 2;handler1.sendMessage(msg);}});}@SuppressLint("HandlerLeak")Handler handler1 = new Handler() {@Overridepublic 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() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {final int position = (int) animation.getAnimatedValue();setCurrentPosition(position % 8);mShouldStartNextTurn = false;}});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic void callback(Bitmap bitmap) {if (null != bitmap) {Message msg = new Message();msg.arg1 = finalI;msg.obj = bitmap;handler.sendMessage(msg);}}});}}};Handler handler = new Handler() {@Overridepublic 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.LuckyViewandroid: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);}/*** 设置控件为正方形*/@Overrideprotected 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);}@Overridepublic 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();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {// 通知关闭线程isRunning = false;}@Overridepublic void run() {// 不断的进行drawwhile (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 {// 获得canvasmCanvas = 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]);// 绘制IcondrawIcon(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/8int 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地址:点击打开链接

Android之九宫格抽奖及大转盘抽奖相关推荐

  1. 抽奖动画大转盘抽奖思路与做法

    抽奖是各类营销活动中最常见的一种形式,本产品需求大致如下:转盘周围跑马灯交替闪烁,点击抽奖,大转盘旋转,调用接口获取抽奖结果,大转盘指针指向对应的奖品.高保如下图1 2.整体思路 本需求要求跑马灯交替 ...

  2. uni-app - 九宫格老虎机抽奖机插件源码(支持服务端API接口控制最终中奖的奖品,自定义组件可随意配置和控制,带组件文档轻松 DIY 自己的营销页抽奖机)幸运抽奖圆形大转盘插件组件

    前言 如果您需要圆形大转盘抽奖机(如下图所示),请访问:这篇文章. 关于九宫格式老虎机宫格跳动抽奖,网上的大部分源码非常乱且无注释,根本无法改造, 本文提供的组件源码,代码干净整洁注释详细,并且配备超 ...

  3. canvas抽奖插件大转盘和九宫格

    下载地址 两款canvas抽奖插件包含大转盘和九宫格// 大转盘抽奖 let luckyWheel = new LuckyCanvas.LuckyWheel({ el: "#my-lucky ...

  4. jquery抽奖转盘java_jquery实现九宫格大转盘抽奖

    下面我们来分享一个九宫格抽奖特效 特效说明: 一款jQuery九宫格大转盘抽奖代码网页特效,点击抽奖按钮开始随机抽奖选择奖品,可设置起点位置.奖品数量.转动次数.中奖位置参数.(兼容测试:IE7及以上 ...

  5. 幸运大转盘抽奖(前端)

    采用Lottery.js插件, 无依赖, 简单易用(复制粘贴就能用) 效果图(可自己写算法定义概率,可自己定义奖项数量和名称) html <!DOCTYPE html> <html ...

  6. php仿京东幸运大转盘抽奖,原生js vue 抽奖插件 仿京东大转盘抽京豆(原创)...

    插件描述:一个基于原生 javript vue2 vue3 的大转盘抽奖插件 更新时间:2020-11-24 00:18:54 在 vue2.x / vue3.x 中使用 方式 1:通过 import ...

  7. html转盘游戏,html5大转盘抽奖实例源码(基于vue.js)

    [实例简介] [调试步骤] # 安装依赖 npm install # 开启本地服务器localhost:8088 npm run dev # 发布环境 npm run build #然后静待你的浏览器 ...

  8. php 打乱数组顺序_PHP实现大转盘抽奖算法

    php中文网最新课程 每日17点准时技术干货分享 本文通过具体的实例向大家介绍了PHP语言实现大转盘抽奖算法,希望对大家学习PHP抽奖有所帮助. 流程: 1.拼装奖项数组: 2.计算概率: 3.返回中 ...

  9. Jquery写的幸运大转盘抽奖实例,用asp.net处理的服务器逻辑,附源码下载

    [实例简介] 该幸运大转盘抽奖实例已实现服务器端的业务逻辑代码,稍加改动就可以应用实际了 文件:590m.com/f/25127180-488779229-66bbf7(访问密码:551685) [实 ...

最新文章

  1. non-member function cannot have cv-qualifier
  2. Sa身份登陆SQL SERVER失败的解决方案
  3. 长沙校园招聘总结-做为技术面试官
  4. MySQL MyISAM/InnoDB高并发优化经验
  5. python游戏猫咪藏在哪个房间_tes体系风格已经定型,EZ加猫咪似乎成唯一解,在藏还是真没了?...
  6. scope python_Python标准库Scope
  7. 在websphere部署完war包后出现com.ibm.ws.jsp.JspCoreException: JSPG0218E异常
  8. mysql使用join和不使用join_在SQL或MySQL中不使用JOIN关键字的联接有问题吗?
  9. 20190908每日一句
  10. 用Neo4j图形数据库打造专属于你的高bigger关系图
  11. win环境下jdk7与jdk8共存问题
  12. 随机密码生成器 java
  13. 30 | 安全运营:“黑灰产”打了又来,如何正确处置?
  14. linux如何彻底删除一个用户
  15. 【2022年第一期 CANN训练营进阶班应用课】第一次大作业
  16. 神经网络中前向传播和反向传播解析
  17. vue中使用Lodop调用打印机打印条形码
  18. 第24篇-极某壁纸结果参数分析
  19. JavaScript注释语句
  20. E212: 无法打开并写入文件

热门文章

  1. 鼠标下面小圆圈脚贴丢了
  2. 蛋壳公寓暴雷,一个将租房做成金融的韭菜联合收割机
  3. ur5+Azure kinect dk 手眼标定
  4. c语言家谱管理系统(包含文件导入导出)
  5. 中国九大名牌背后的经典故事
  6. 苹果手机录屏在哪里_小米,苹果录屏哪个好?独家整理手机录屏方法,那你知道哪几种?...
  7. windows10 进入BIOS
  8. android 程序调用wps,Android在调用像WPS这种第三方软件打开word时遇到ActivityNotFoundException...
  9. openwrt定时检测IP地址,发生变化时把IP地址发送到手机上
  10. 携手共建国产云生态,巨杉数据库与华云数据完成产品互认证