最近在工作中碰到了抽奖转盘的类似需求,本来打算github找找,结果发现好多都是转盘内容固定,不支持动态改变的,于是就亲自尝试一番,也就当练习了下自定义view。作为应届,知识还是不够丰富的,所以就简单的实现了下。

1、效果图

由于gif图内存有限制,请观看视屏。
传送门

2、实现思路

其实自定义view的难点一部分在于大量数学计算、一部分在于view的分解、

(1)view的分解

1、画圆
2、画线(这里有个小技巧:循环旋转画布为相应的角度即可)
3、绘制文字(小技巧:文字居中的处理,获得文字的大小,设置坐标)

(2)数学计算

本自定义view还算比较简单
1、view的默认大小:手机屏幕宽高中最小值的五分之四
2、角度计算360/份数(数组内容个数)
3、圆整分

其实一些奇数是不能整分的例如7,360是整除不尽的这里就采取循环设置前六分为 360/7取整的,最后一份为剩余的。其实设置份数为n 每一份都是采取这样的策略,前面n-1分均分。最后一份为360减去剩余的。

4、文字的居中绘制

这里牵涉到一些小技巧,画布旋转n度时画线,则旋转n/2绘制文字。而且我们还可以会的绘制文字的一个Rect,这时可计算出文字坐标。在居中显示即可。

5、播放动画随机旋转位置或者指定旋转位置(如下图)

假如位置0、1,我们随机数为1,则旋转的圈数为:圈数*360+a(a需要我们手动计算下,圈数随便指定即可,只是相当于多转了n圈)

3、其他知识点

1、属性动画ValueAnimator的灵活运用
2、自定义view的默认大小处理(wrap-content)
ps:这里考验掌握的知识

4、源码及其使用
/*** Created by sunnyDay on 2019/10/22 10:54* 幸运转盘*/
public class LuckyPlate extends View {private static final String TAG = "LuckyPlateLog";private OnAnimatorListener mOnAnimatorListener;private int division = 2;private String[] mContents;public int DEFAULT_VIEW_SIZE;private int mScreenWidth;private int mScreenHeight;private int viewWidth;private int viewHeight;private Paint mCirclePaint;private Paint mLinePaint;private Paint mTextPaint;private int randomPos;public LuckyPlate(Context context) {this(context, null);}public LuckyPlate(Context context, AttributeSet attrs) {this(context, attrs, 0);}public LuckyPlate(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);dealWithPadding();int pointX = viewWidth / 2;int pointY = viewHeight / 2;canvas.translate(pointX, pointX);canvas.drawCircle(0, 0, pointX, mCirclePaint);canvas.drawLine(0, 0, 0, -pointY, mLinePaint);divideCircle(canvas, pointX);}/*** wrap_content处理* 默认处理为手机屏幕宽高中的最小值*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);DEFAULT_VIEW_SIZE = Math.min(mScreenWidth, mScreenHeight) * 4 / 5;int widthMode = MeasureSpec.getMode(widthMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heighthMode = MeasureSpec.getMode(heightMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);if (widthMode == MeasureSpec.AT_MOST && heighthMode == MeasureSpec.AT_MOST) {// 用户宽高都设置为 wrap_content时setMeasuredDimension(DEFAULT_VIEW_SIZE, DEFAULT_VIEW_SIZE);} else if (widthMode == MeasureSpec.AT_MOST) {// 当宽设置了wrap_content时setMeasuredDimension(DEFAULT_VIEW_SIZE, heightSize);} else if (heighthMode == MeasureSpec.AT_MOST) {// 当高设置了wrap_content时setMeasuredDimension(widthSize, DEFAULT_VIEW_SIZE);} else {setMeasuredDimension(DEFAULT_VIEW_SIZE, DEFAULT_VIEW_SIZE); //默认大小,new对象的方式时}}private void init() {mScreenHeight = getResources().getDisplayMetrics().heightPixels;mScreenWidth = getResources().getDisplayMetrics().widthPixels;mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);mCirclePaint.setColor(Color.BLUE);mCirclePaint.setStyle(Paint.Style.STROKE);mCirclePaint.setStrokeWidth(3);mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);mLinePaint.setColor(Color.GRAY);mLinePaint.setStyle(Paint.Style.STROKE);mLinePaint.setStrokeWidth(3);mTextPaint = new Paint();mTextPaint.setColor(Color.BLACK);mTextPaint.setStyle(Paint.Style.FILL);mTextPaint.setTextSize(40);mCirclePaint.setTextSkewX(.5f);}/*** 吧圆划分成整块* ps:* 1、360除不尽的奇数最后一块会多几度* 2、绘制文字居中。循环旋转画布指定角度n,旋转n/2时绘制文字,旋转n度时绘制线。*/private void divideCircle(Canvas canvas, int radius) {if (mContents == null) {dealWithEmptyStringArr();}division = mContents.length;int flag = 0;float textAngle = 360 / division / 2;for (int i = 0; i < division * 2; i++) {if (i == division * 2 - 1) {canvas.rotate(360 - textAngle * (division * 2 - 1));} else {canvas.rotate(textAngle);flag++;if (flag % 2 != 0) {Rect rect = new Rect();mTextPaint.getTextBounds(mContents[i / 2], 0, mContents[i / 2].length(), rect);canvas.drawText(mContents[i / 2], -rect.width() / 2, -(radius - rect.height() - 100), mTextPaint);} else {canvas.drawLine(0, 0, 0, -radius, mLinePaint);}}}}private void dealWithEmptyStringArr() {mContents = new String[]{"火锅", "火锅", "火锅", "火锅"};}private void dealWithPadding() {final int paddingLeft = getPaddingStart();final int paddingRight = getPaddingEnd();final int paddingTop = getPaddingTop();final int paddingBottom = getPaddingBottom();viewWidth = getWidth() - paddingLeft - paddingRight;viewHeight = getHeight() - paddingTop - paddingBottom;}public void setContents(String[] contents) {mContents = contents;invalidate();}/*** @param pos 指定位置* @functuion 转动到指定位置(索引从0开始)* ps:如果 pos = -1 则随机转动,如果指定某个值,则转到某个指定区域。*/public void startRotate(int pos) {if (pos < division) {int targetItem;ValueAnimator animator;if (pos == -1) {//随机randomPos = randomPos();targetItem = division - 1 - randomPos;} else {//用户指定位置targetItem = division - 1 - pos;}animator = ValueAnimator.ofFloat(0, 360 * 5 + 360 / division / 2 + targetItem * (360 / division));animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {float degree = (float) animation.getAnimatedValue();setRotation(degree);}});animator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {mOnAnimatorListener.finish(randomPos);}});animator.setInterpolator(new AccelerateDecelerateInterpolator());animator.setDuration(5000);animator.start();} else {throw new IllegalArgumentException("param out of bound");}}public int randomPos() {return new Random().nextInt(division);}public void addOnAnimatorListener(OnAnimatorListener onAnimatorListener) {this.mOnAnimatorListener = onAnimatorListener;}public interface OnAnimatorListener {void finish(int randomPos);}
}

使用参考:
简单使用

5、小结

简单的实现了下,为了方便没有自定义xml属性啥的。发现对知识的了解又加深了一步,快乐啦!溜溜球。。。

6、使用

1、如果想直接拿来用,需求和这里一致,那直接把类复制走即可。参考使用案例就o了
2、也欢迎大家交流学习,改写添加图片等新的功能。
项目源码

自定义View:常见抽奖转盘的实现相关推荐

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

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

  2. Android 自定义View实现QQ运动积分抽奖转盘

    因为偶尔关注QQ运动, 看到QQ运动的积分抽奖界面比较有意思,所以就尝试用自定义View实现了下,原本想通过开发者选项查看下界面的一些信息,后来发现积分抽奖界面是在WebView中展示的,应该是在H5 ...

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

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

  4. android自定义抽奖转盘

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

  5. 【鸿蒙】HarMonyOS的自定义组件之抽奖大转盘

    1. 介绍 当系统提供的组件无法满足设计需求时,您可以创建自定义组件,根据设计需求自定义组件的属性及响应事件,并绘制组件.自定义组件是在组件预留的两个自定义图层中实现绘制,通过addDrawTask方 ...

  6. Android 常见界面控件(ListView、RecyclerView、自定义View篇)

    Android 常见界面控件(ListView.RecyclerView.自定义View篇) 目录 3.3 ListView的使用 3.3.1 ListView控件的简单使用 3.3.2 常用数据适配 ...

  7. html旋转代码_用CSS实现一个抽奖转盘(附详细代码+思路)

    原文:https://www.cnblogs.com/wenruo/p/9732704.html 先上效果 基本是用CSS实现的,没有用图片,加一丢丢JS.不过没有考虑太多兼容性. 首先画一个转盘 & ...

  8. 如何用python画转盘_如何用ppt做一个抽奖转盘 看完你学会了么

    现在抽奖转盘是很常见的,有时候公司办活动也会有抽奖活动,如果让自己做一个抽奖转盘,应该怎么做? 操作方法 01 打开ppt,把幻灯片版式设置成空白的,然后点击插入,选择图表. 02 选择饼图,用第一种 ...

  9. 详解与重构hyman《Android SurfaceView实战 打造抽奖转盘》

    详解与重构hyman<Android SurfaceView实战 打造抽奖转盘> 作者:邵励治 一.概述--关于SurfaceView您不得不知道的二三事 1.SurfaceView是干什 ...

最新文章

  1. 关于Visual Studio2019的4996错误警告解决方法
  2. Practice:Office2010中OneNote与outlook的协同工作
  3. JSP简单练习-省略显示长字符串
  4. C# Redis实战(七)
  5. linux安装mysql8依赖的环境_CentOS Linux release 8 安装mysql8.
  6. 屌丝程序员的那些事(一)-毕业那年
  7. Effective Java~42. Lambda 优于匿名类
  8. C# dll加载,抽象方法的使用
  9. 极简代码(五)—— 斐波那契数列
  10. Matplotlib模块的使用
  11. python列表姓氏,Python程序可以打印完整姓氏的名字的缩写吗?
  12. html清除图层,ps按delete不能删除图层怎么办?
  13. JS中常见的兼容写法
  14. 一维卷积神经网络在近红外光谱分析中的应用
  15. rpg学院 unity_Unity3d - RPG项目学习笔记(一)
  16. python中筛选内容_Python中数据筛选代码实现
  17. 云计算现在前景如何?怎么转型成为云计算工程师?
  18. CATIA许可证安装,破解文件运行不了直接跳到finish问题
  19. 视频教程-黑客基础——爬虫(从理论剖析到实战演练)-大数据
  20. 项目管理PMP多大作用?

热门文章

  1. (九)GD、L1和L2、MAP、MLE、Lasso
  2. 互联网金融时代,必看的六种理财模式------------王艾老哥浅析
  3. 大学计算机三级网络技术,考前数天如何突破性通过计算机等级考试之三级网络技术篇...
  4. 分享Windows版pgadmin(v4.17)
  5. Python识别中文
  6. showdoc安装与脚本生成文档
  7. java64 压缩包,qq64位下载-rar 64位 v5.21 免费版
  8. 【大数据相关】电商大数据之用户画像介绍
  9. 区块链(二、智能合约的开发)
  10. web 树莓派zero_树莓派 零 Raspberry Pi Zero 网络解决方案