效果图:

好久没有写博客了,在帮朋友修改项目的时候偶然发现了抽奖转盘,觉得挺好玩儿,就自己写了一个,为此我还特意贡献出了自己的女神们,哈哈。。。
项目参考了鸿洋的博客,在此特别感谢鸿洋大神的帮助,参考博客:http://blog.csdn.net/lmj623565791/article/details/41722441

这个自定义控件与鸿洋所写的不同点在于:
鸿洋牌抽奖转盘实现方式:
1.鸿洋采用继承并重写SurfaceView来实现,通过在子线程中不断绘制来实现转盘旋转。
2.抽奖图片采用正视角,也就是旋转过程中所看到的图片都是竖立的。
3.转盘集成在一个类中,引用时需要在xml中添加点击抽奖图片和指针。
我自己的实现方式:
1.采用传统的继承View的方式来绘制转盘,在子线程中发送旋转指令,然后在UI线程中使用View旋转动画来进行旋转。—-View旋转动画底层也是通过重新绘制实现
2.抽奖图片采用相对模块正视角。—这个纯属个人视觉爱好
3.将点击抽奖图片和绘制的转盘以及抽奖回调封装到一起,方便直接调用。
我将这个控件分布于三个类中,以下提供代码:
绘制转盘的LuckyRoller类:

package com.lxh.custom.view.luckRoller;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import java.util.List;/*** Created by lxh on 2017/3/22.* QQ-632671653*/public class LuckyRoller extends View {/*** padding值*/private int mPaddingLeft;/*** 控件中心坐标*/private int centerX, centerY;/*** 控件宽度*/private int with;/*** 外圆环宽度*/private int circleWith;/*** 圆环半径*/private int circleRadius;/*** 转盘半径*/private int rollerRadius;/*** 绘制盘块的范围*/private RectF mRange;/*** 盘块的个数*/private int mItemCount;/*** 与文字对应图片的bitmap数组*/private Bitmap[] mImgsBitmap;/*** 转盘内容实体集合*/private List<LuckyBean> luckyBeanList;/*** 文字的大小*/private float mTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());public LuckyRoller(Context context) {super(context);}public LuckyRoller(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public LuckyRoller(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);with = MeasureSpec.getSize(widthMeasureSpec);//控件宽度setMeasuredDimension(with, with);//重设控件宽高centerX = getMeasuredWidth() / 2; //控件X坐标centerY = getMeasuredHeight() / 2;//控件Y坐标circleWith = with / 12;     //外圆环的宽度mPaddingLeft = getPaddingLeft();  //控件padding值circleRadius = centerX - mPaddingLeft;  //圆环的半径rollerRadius = circleRadius - circleWith / 2;  //扇形块的半径luckyBeanList = LuckRollerView.dataList;   //填充的数据if (luckyBeanList!=null&&luckyBeanList.size()>=1){mItemCount = luckyBeanList.size();if (0 != mItemCount) {// 圆弧的绘制范围mRange = new RectF(centerX - circleRadius + circleWith / 2, centerY - circleRadius + circleWith / 2,centerX + circleRadius - circleWith / 2, centerY + circleRadius - circleWith / 2);// 初始化图片mImgsBitmap = new Bitmap[mItemCount];for (int i = 0; i < mItemCount; i++) {mImgsBitmap[i] = BitmapFactory.decodeResource(getResources(), luckyBeanList.get(i).getImg());}}}}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (0 != mItemCount) {Paint paint = new Paint();drawCircle(canvas, paint);Paint rollerPaint = new Paint();rollerPaint.setAntiAlias(true);//抗锯齿rollerPaint.setDither(true);//防抖动Paint mTextPaint = new Paint();mTextPaint.setColor(0xFFffffff);mTextPaint.setTextSize(mTextSize);float tmpAngle = 0;float sweepAngle = (float) (360 / 6);for (int i = 0; i < 6; i++) {drawRoller(canvas, rollerPaint, i, tmpAngle, sweepAngle);drawText(tmpAngle, sweepAngle, luckyBeanList.get(i).getName(), canvas, mTextPaint);drawIcon(tmpAngle, mImgsBitmap[i], canvas);tmpAngle += sweepAngle;}}}/*** 绘制文本** @param startAngle* @param sweepAngle* @param string*/private void drawText(float startAngle, float sweepAngle, String string, Canvas mCanvas, Paint mTextPaint) {Path path = new Path();path.addArc(mRange, startAngle, sweepAngle);float textWidth = mTextPaint.measureText(string);// 利用水平偏移让文字居中float hOffset = (float) (rollerRadius * Math.PI / mItemCount - textWidth / 2);// 水平偏移float vOffset = rollerRadius / 6;// 垂直偏移mCanvas.drawTextOnPath(string, path, hOffset, vOffset, mTextPaint);}/*** 根据给定的宽和高进行缩放** @param origin    原图* @param newWidth  新图的宽* @param newHeight 新图的高* @return new Bitmap*/private Bitmap scaleBitmap(Bitmap origin, int newWidth, int newHeight) {if (origin == null) {return null;}int height = origin.getHeight();int width = origin.getWidth();float scaleWidth = ((float) newWidth) / width;float scaleHeight = ((float) newHeight) / height;Matrix matrix = new Matrix();matrix.postScale(scaleWidth, scaleHeight);Bitmap newBM = Bitmap.createBitmap(origin, 0, 0, width, height, matrix, false);return newBM;}/*** 绘制icon图片** @param startAngle* @param bitmap* @param mCanvas*/private void drawIcon(float startAngle, Bitmap bitmap, Canvas mCanvas) {// 设置图片的宽度为直径的1/8int imgWidth = rollerRadius / 4;// 确定绘制图片的位置int x = centerX;int y = (int) (centerY - rollerRadius / 1.8);//将位图进行缩放Bitmap mBitmap = scaleBitmap(bitmap, imgWidth, imgWidth);mCanvas.save();//保存当前画布状态mCanvas.rotate(startAngle + 120, centerX, centerY);//画布绕中心点旋转mCanvas.drawBitmap(mBitmap, x - imgWidth / 2, y - imgWidth / 2, null);//绘制位图mCanvas.restore();//恢复画图状态到保存前}/*** 绘制圆环** @param mCanvas* @param mPaint*/private void drawCircle(Canvas mCanvas, Paint mPaint) {mPaint.setAntiAlias(true);//抗锯齿mPaint.setColor(Color.BLUE);mPaint.setStrokeWidth(circleWith);mPaint.setStyle(Paint.Style.STROKE);mCanvas.drawCircle(centerX, centerY, circleRadius - circleWith / 2, mPaint);}/*** 绘制转盘中的扇形** @param mCanvas* @param mPaint* @param i* @param tmpAngle* @param sweepAngle*/private void drawRoller(Canvas mCanvas, Paint mPaint, int i, float tmpAngle, float sweepAngle) {// 绘制模块mPaint.setColor(luckyBeanList.get(i).getColor());mCanvas.drawArc(mRange, tmpAngle, sweepAngle, true, mPaint);}
}

转盘内容实体类LuckyBean:

package com.lxh.custom.view.luckRoller;import android.graphics.Bitmap;/*** Created by lxh on 2017/3/29.* QQ-632671653*/public class LuckyBean {private int img;private String name;private int Color;private Bitmap bitmap;public int getImg() {return img;}public void setImg(int img) {this.img = img;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getColor() {return Color;}public void setColor(int color) {Color = color;}public Bitmap getBitmap() {return bitmap;}public void setBitmap(Bitmap bitmap) {this.bitmap = bitmap;}
}

继承点击抽奖图片和转盘,以及旋转实现的LuckRollerView:

package com.lxh.custom.view.luckRoller;import android.content.Context;
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.lxh.custom.R;
import java.util.List;/*** Created by lxh on 2017/3/24.* QQ-632671653*/public class LuckRollerView extends RelativeLayout {/*** 转盘控件*/private LuckyRoller luckyRoller;/*** 开始图片*/private ImageView imageView;/*** 旋转角度*/private int rotatiion = 0;/*** 是否循环标志*/private boolean isRunning = false;/*** 结果回调监听*/private OnLuckyRollerListenner onLuckyRollerListenner;/*** 是否已经开始*/private boolean isStart = false;/*** 是否第一次开始*/private boolean isFirst = true;/*** 速度控制*/private int speed = 0,sleep = 4;/*** 转盘数据*/public static List<LuckyBean> dataList;public LuckRollerView(Context context) {super(context);}public LuckRollerView(Context context, AttributeSet attrs) {super(context, attrs);}public LuckRollerView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}/*** 利用handler切换到UI线程进行转盘旋转*/private Handler handler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case 1:rotatiion += speed;luckyRoller.setRotation(rotatiion);break;}}};/*** 任务线程*/private Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (isRunning) {if (isStart) {handler.sendEmptyMessage(1);try {thread.sleep(sleep);} catch (InterruptedException e) {e.printStackTrace();}}}}});/*** 初始化控件* @param context*/private void initView(Context context) {luckyRoller = new LuckyRoller(context);LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);luckyRoller.setLayoutParams(layoutParams);imageView = new ImageView(context);LayoutParams imgLp = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);imgLp.addRule(RelativeLayout.CENTER_IN_PARENT);imageView.setLayoutParams(imgLp);imageView.setImageResource(R.mipmap.start);imageView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (isStart) {pause();} else {startOrResume();}}});addView(luckyRoller);addView(imageView);}/*** 根据旋转角度确定选中区域* @param rotatiion*/public void calInExactArea(int rotatiion) {// 让指针从水平向右开始计算float rotate = rotatiion+90;int mItemCount = dataList.size();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)) {if (onLuckyRollerListenner!=null){onLuckyRollerListenner.onFinish(dataList.get(i).getName());}return;}}}/*** 开始或者恢复旋转*/private void startOrResume() {if (isFirst) {isRunning = true;isStart = true;isFirst = false;thread.start();} else {resume();}countDownTimer.start();stopViewTimer.start();}private void resume() {isStart = true;}/*** 暂停*/private void pause() {isStart = false;speed = 0;imageView.setImageResource(R.mipmap.start);calInExactArea(rotatiion);}/*** 为控件设置数据* @param context* @param data*/public void setData(Context context,List<LuckyBean> data){this.dataList = data;initView(context);}/*** 通过计时器来设定速度和最短旋转时间*/private CountDownTimer countDownTimer = new CountDownTimer(sleep*1000,1000) {@Overridepublic void onTick(long millisUntilFinished) {speed+=1;if (sleep>1)sleep-=1;imageView.setClickable(false);imageView.setImageResource(R.mipmap.stop2);}@Overridepublic void onFinish() {imageView.setClickable(true);imageView.setImageResource(R.mipmap.stop);}};/*** 通过计时器来设定旋转最长时限*/private CountDownTimer stopViewTimer = new CountDownTimer(10000,1000) {@Overridepublic void onTick(long millisUntilFinished) {}@Overridepublic void onFinish() {if (isStart){imageView.performClick();}}};/*** 中断线程,回收内存*/public void destory(){thread.interrupt();}/*** 设置监听* @param onLuckyRollerListenner*/public void setOnLuckyRollerListenner(OnLuckyRollerListenner onLuckyRollerListenner) {this.onLuckyRollerListenner = onLuckyRollerListenner;}public interface OnLuckyRollerListenner{void onFinish(String data);}}

使用方式:
1.在xml中调用:

<com.lxh.custom.view.luckRoller.LuckRollerViewandroid:id="@+id/luckRollerView"android:layout_width="500dp"android:layout_height="500dp"/>

2.在相应java类中进行初始化:

/*** 与文字对应的图片*/private int[] mImgs = new int[]{R.mipmap.fanbingbing, R.mipmap.libb,R.mipmap.liuss, R.mipmap.lyf, R.mipmap.dlrb,R.mipmap.linzl};/*** 抽奖的文字*/private String[] mStrs = new String[]{"范冰冰", "李冰冰", "刘诗诗", "刘亦菲","迪丽热巴", "林志玲"};/*** 每个盘块的颜色*/private int[] mColors = new int[]{0xFFFFC300, 0xFFF17E01, 0xFFFFC300,0xFFF17E01, 0xFFFFC300, 0xFFF17E01};private void initData(){for (int i = 0;i<mStrs.length;i++){LuckyBean luckyBean = new LuckyBean();luckyBean.setName(mStrs[i]);luckyBean.setColor(mColors[i]);luckyBean.setImg(mImgs[i]);luckyBeanList.add(luckyBean);}}private void initView() {initData();luckRollerView = (LuckRollerView) findViewById(R.id.luckRollerView);luckRollerView.setData(mContext, luckyBeanList);luckRollerView.setOnLuckyRollerListenner(new LuckRollerView.OnLuckyRollerListenner() {@Overridepublic void onFinish(String data) {Toast.makeText(mContext, "恭喜你抽中了-" + data + "-", Toast.LENGTH_LONG).show();}});}

以上代码都有详细注释,因此就不在赘述。已将项目完整代码上传至github。有需要可自行下载。
github地址:https://github.com/lxh632671653/custom

这个控件已经写好很久了,因为私人原因未能及时发布博客,望各位大佬海涵。谢谢!技术交流请加QQ:632671653

Android-自定义幸运抽奖转盘相关推荐

  1. Android开发:抽奖转盘的实现

    故事的开始 最近有个需求,支付成功的时候加个抽奖轮盘.类似问卷星提交后的那种东西,翻了一下gayhub,下面给出自己的实现思路. 写在题前 这东西是在github上一个项目是拓展的.但是实现时间和下载 ...

  2. 掘金—幸运抽奖转盘部分HTML+CSS代码

    八月份的时候有幸参加了字节前端青训营项目,从几乎没有接触过代码的小白,开始接触前端开发,并对其有了一点基础的了解.最终的结业项目是模拟掘金社区的幸运抽奖,其中我负责的是抽奖转盘的HTML和CSS部分, ...

  3. android自定义抽奖,Android 自定义View 抽奖大转盘(2)

    这是转盘的第二个版本,添加了外围的圆圈 第一个demo在这儿可以找到 镇楼图 S171011-11370203.jpg 项目的本来来源来自于 添加外围的圆圈,主要由两部分组成 1.画小圆.2.圆盘位置 ...

  4. android自定义大转盘,Android 自定义View 抽奖大转盘(1)

    站在别人的肩膀上慢慢前行 只是部分的转盘主要功能的实现,其他的东西可以慢慢填上,这里做一个简单的介绍 镇楼图 S71010-17315559.jpg github链接 https://github.c ...

  5. 完整~小程序canvas制作幸运抽奖转盘

    小程序转盘完整版 最近在做一款小程序幸运转盘抽奖,遇到了不少坑,分享一下 先看下效果图 wxml里面比较简单,但是canvas在真机上面显示会有问题,只需要生成你想要的canvas后转化为图片 < ...

  6. android自定义抽奖转盘

    项目中有用到抽奖转盘,网上找的demo有些不合设计的要求(不能随意添加转盘中item的个数,不能以上层view滚动等),于是自己尝试写了个自定义的抽奖转盘,方便以在别的项目中更改使用,大致的效果如下图 ...

  7. android+清除循环动画,android自定义View之(4)-一键清除动画

    android自定义View之(四)------一键清除动画 1.前言: 自己也是参考别人的一些自定义view例子,学习了一些基本的自定义view的方法.今天,我参考了一些资料,再结合自已的一些理解, ...

  8. android自定义View之(四)------一键清除动画

    1.前言: 自己也是参考别人的一些自定义view例子,学习了一些基本的自定义view的方法.今天,我参考了一些资料,再结合自已的一些理解,做了一个一键清除的动画.当年,我实现这个是用了几张图片,采用F ...

  9. android自定义抽奖,Android自定义view制作抽奖转盘

    本文实例为大家分享了Android自定义view制作抽奖转盘的具体代码,供大家参考,具体内容如下 效果图 TurntableActivity package com.bawei.myapplicati ...

  10. 基于 SurfaceView 详解 android 幸运大转盘,附带实例app

    基于 SurfaceView 详解 android 幸运大转盘,附带实例app 首先说一下,幸运大转盘,以及SurfaceView是在看了也为大神的博客,才有了比较深刻的理解,当然这里附上这位大神的博 ...

最新文章

  1. 看完这篇Exception 和 Error,和面试官扯皮就没问题了
  2. 负载测试值mpstat的使用技巧
  3. 暴力探测蓝牙设备工具redfang
  4. 【29.70%】【codeforces 723D】Lakes in Berland
  5. 计算机用户域怎么删除,如何查找并删除AD域中多余的计算机帐号?
  6. Floating-Rate Note - FRN
  7. IT英语职场之网管英语大全
  8. why my SAP UI5 filter by titleID does not work
  9. 构建Spring Boot RESTful服务+ Spring Boot执行器
  10. linux shell ls -l,linux之ls -l|grep ^-|wc -l命令 Shell 中常見的日志統計方法
  11. 【HDU - 5015 】233 Matrix (矩阵快速幂)
  12. 一道内存分配的面试题后续
  13. caged系统pdf_建筑行业单词中英文对照教材.pdf
  14. [Learn Notes] CSS学习笔记
  15. 2017.4.5 假期的宿舍 思考记录
  16. 【深度学习】图像超分实验:SRCNN/FSRCNN
  17. 如何在网页上添加分享按钮
  18. Stochastic Weight Averaging (SWA) 随机权重平均
  19. xilinx--IOB(1)
  20. opencv模拟景深效果

热门文章

  1. 微博已成中国和世界真正的“连接器”
  2. NetworkX中文使用手册
  3. android 树莓派 图片,Android Things:树莓派3上手就是这么简单
  4. 记YY的一次面试经历
  5. 编程作业(python)| 吴恩达 机器学习(6)支持向量机 SVM
  6. iOSSafari不兼容正则表达式的断言匹配及解决办法
  7. 怎样用投资的逻辑来填报志愿?
  8. 两点GPS经纬度获取局部位置的理论
  9. 大数据与信息安全(六)天网系统与大数据 大数据
  10. VUE3模板,JSX,JSV