Android使用surfaceView自定义抽奖大转盘

使用surfaceView自定义抽奖大转盘

话不多说,先上效果图

完整代码地址欢迎start

实现思路以及过程

1、首先了解SurfaceView的基本用法,它跟一般的View不太一样,采用的双缓存机制,可以在子线程中绘制View,不会因为绘制耗时而失去流畅性,这也是选择使用SurfaceView去自定义这个抽奖大转盘的原因,毕竟绘制这个转盘的盘块,奖项的图片和文字以及转动都是靠绘制出来的,是一个比较耗时的绘制过程。

2、使用SurfaceView的一般模板样式

一般会用到的成员变量

private SurfaceHolder mSurfaceHolder; private Canvas mCanvas;

初始化常亮

public SurfaceViewTemplate(Context context,AttributeSet attrs) { super(context, attrs); //初始化 mSurfaceHolder = getHolder(); mSurfaceHolder.addCallback(this); //设置可获得焦点 setFocusable(true); setFocusableInTouchMode(true); //这是常亮 setKeepScreenOn(true); }

给SurfaceView添加callback实现其中三个方法

@Override public void surfaceCreated(SurfaceHolder surfaceHolder) { //surface创建的时候 mThread = new Thread(this); //创建的时候就开启线程 isRunning = true; mThread.start(); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { //变化的时候 } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { //销毁的时候 关闭线程 isRunning = false; }

在子线程中定义一个死循环不断的进行绘制

@Override public void run() { //在子线程中不断的绘制 while (isRunning) { draw(); } } private void draw() { try { mCanvas = mSurfaceHolder.lockCanvas(); if (null != mCanvas) { //避免执行到这里的时候程序已经退出 surfaceView已经销毁那么获取到canvas为null } } catch (Exception e) { //异常可以不必处理 } finally { //一定要释放canvas避免泄露 mSurfaceHolder.unlockCanvasAndPost(mCanvas); } }

3、了解了SurfaceView的基本用法之后,接下来实现抽奖转盘

首先测量整个View的范围,设置成正方形

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //直接控制Span为正方形 int width = Math.min(getMeasuredWidth(), getMeasuredHeight()); mPadding = getPaddingLeft(); //直径 mRadius = width - mPadding * 2; //设置中心点 mCenter = width / 2; //设置成正方形 setMeasuredDimension(width, width); }

在SurfaceView创建的时候初始化画笔矩形范围等,见代码

public void surfaceCreated(SurfaceHolder surfaceHolder) { //初始化绘制Span的画笔 mSpanPaint = new Paint(); mSpanPaint.setAntiAlias(true); mSpanPaint.setDither(true); //初始化绘制文本的画笔 mTextPaint = new Paint(); mTextPaint.setTextSize(mTextSize); mTextPaint.setColor(0Xffa58453); //绘制圆环的画笔 mCirclePaint = new Paint(); mCirclePaint.setAntiAlias(true); mCirclePaint.setColor(0xffdfc89c); //初始化Span的范围 mRectRange = new RectF(mPadding, mPadding, mPadding + mRadius, mPadding + mRadius); mRectCircleRange = new RectF(mPadding * 3 / 2, mPadding * 3 / 2, getMeasuredWidth() - mPadding * 3 / 2, getMeasuredWidth() - mPadding * 3 / 2); //初始化bitmap mImgIconBitmap = new Bitmap[mSpanCount]; //将奖项的icon存储为Bitmap for (int i = 0; i < mSpanCount; i++) { mImgIconBitmap[i] = BitmapFactory.decodeResource(getResources(), mPrizeIcon[i]); } //surface创建的时候 mThread = new Thread(this); //创建的时候就开启线程 isRunning = true; mThread.start(); }

接下来就是在开启的子线程中进行绘制

@Override public void run() { //在子线程中不断的绘制 while (isRunning) { //保证绘制不低于50毫秒 优化性能 long start = SystemClock.currentThreadTimeMillis(); draw(); long end = SystemClock.currentThreadTimeMillis(); if ((end - start) < 50) { //休眠到50毫秒 SystemClock.sleep(50 - (end - start)); } } }

重点就在draw()方法中了下面就实现draw方法:

注意:避免mCanvas带来的内存泄漏

try { mCanvas = mSurfaceHolder.lockCanvas(); if (null != mCanvas) { //避免执行到这里的时候程序已经退出 surfaceView已经销毁那么获取到canvas为null //绘制背景 drawBg(); //绘制圆环 mCanvas.drawCircle(mCenter, mCenter, mRadius / 2 + mPadding / 20, mCirclePaint); drawSpan(); } } catch (Exception e) { //异常可以不必处理 } finally { //一定要释放canvas避免泄露 mSurfaceHolder.unlockCanvasAndPost(mCanvas); }

画背景:

//绘制背景 private void drawBg() { //背景设置为白色 mCanvas.drawColor(0xffffffff); mCanvas.drawBitmap(mSpanBackground, null, new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2), mSpanPaint); }

参数解释:

mSpanBackground背景图片 new RectF(mPadding / 2, mPadding / 2, getMeasuredWidth() - mPadding / 2, getMeasuredHeight() - mPadding / 2) //限制背景在一个矩形范围之类

绘制内圆环

mCanvas.drawCircle(mCenter, mCenter, mRadius / 2 + mPadding / 20, mCirclePaint);

绘制中间八个盘块

//定义一个变量临时记录开始转动的角度 float tempAngle = mStartSpanAngle; //每个盘块所占的角度 CIRCLE_ANGLE = 360 float sweepAngle = CIRCLE_ANGLE / mSpanCount; //循环绘制八个板块 for (int i = 0; i < mSpanCount; i++) { //设置每个盘块画笔的颜色 mSpanPaint.setColor(mSpanColor[i]); //绘制扇形盘块,第四个参数为true就是扇形否则就是弧形 mCanvas.drawArc(mRectCircleRange, tempAngle, sweepAngle, true, mSpanPaint); //绘制文字 drawText(tempAngle, sweepAngle, mPrizeName[i]); //绘制奖项Icon drawPrizeIcon(tempAngle, mImgIconBitmap[i]); //改变角度 tempAngle += sweepAngle; }

绘制文字

文字绘制成圆环形状,根据path绘制文字

private void drawText(float tempAngle, float sweepAngle, String text) { //绘制有弧度的文字 根据path绘制文字的路径 Path path = new Path(); path.addArc(mRectRange, tempAngle, sweepAngle); //让文字水平居中 那绘制文字的起点位子就是 弧度的一半 - 文字的一半 float textWidth = mTextPaint.measureText(text); float hOval = (float) ((mRadius * Math.PI / mSpanCount / 2) - (textWidth / 2)); float vOval = mRadius / 15;//竖直偏移量可以自定义 mCanvas.drawTextOnPath(text, path, hOval, vOval, mTextPaint); //第三个四个参数是竖直和水平偏移量 }

绘制盘块中的奖品icon图片

private void drawPrizeIcon(float tempAngle, Bitmap bitmap) { //图片的大小设置成直径的1/8 int iconWidth = mRadius / 20; //根据角度计算icon中心点 //角度计算 1度 == Math.PI / 180 double angle = (tempAngle + CIRCLE_ANGLE / mSpanCount / 2) * Math.PI / 180; //根据三角函数,计算中心点(x,y) int x = (int) (mCenter + mRadius / 4 * Math.cos(angle)); int y = (int) (mCenter + mRadius / 4 * Math.sin(angle)); //定义一个矩形 限制icon位置 RectF rectF = new RectF(x - iconWidth, y - iconWidth, x + iconWidth, y + iconWidth); mCanvas.drawBitmap(bitmap, null, rectF, null); }

大致的绘制基本完成,重点就是通过改变开始转动的角度让转盘转动起来。

mStartSpanAngle += mSpeed;//mSpeed的数值控制转动的速度 //声明的一个结束标志 if (isSpanEnd) { mSpeed -= 1; } if (mSpeed <= 0) { //停止旋转了 mSpeed = 0; isSpanEnd = false; //定义一个回调,监控转盘停止转动 mSpanRollListener.onSpanRollListener(mSpeed); }

定义一个方法, 启动转盘

//抽奖转盘重点就在这里,根据自己传入的index控制抽到的奖品 public void luckyStart(int index) { //根据index控制停留的位置 angle 是每个奖品所占的角度范围 float angle = CIRCLE_ANGLE / mSpanCount; //计算指针停留在某个index下的角度范围HALF_CIRCLE_ANGLE=180度 float from = HALF_CIRCLE_ANGLE - (index - 1) * angle; float end = from + angle; //设置需要停下来的时候转动的距离 保证每次不停留的某个index下的同一个位置 float targetFrom = 4 * CIRCLE_ANGLE + from; float targetEnd = 4 * CIRCLE_ANGLE + end;//最终停下来的位置在from-end之间,4 * CIRCLE_ANGLE 自定义要多转几圈 //计算要停留下来的时候速度的范围,这里注意:涉及到等差数列的公式,因为涉及到让转盘停止转动是使mSpeed-=1;所以它是从 vFrom--0等差递减的一个过程,所以可以算出来vFrom,同理计算出vEnd float vFrom = (float) ((Math.sqrt(1 + 8 * targetFrom) - 1) / 2); float vEnd = (float) ((Math.sqrt(1 + 8 * targetEnd) - 1) / 2); //在点击开始转动的时候 传递进来的index值就已经决定停留在那一项上面了 mSpeed = vFrom + Math.random() * (vEnd - vFrom); isSpanEnd = false; }

停止转动

public void luckStop() { //在停止转盘的时候强制吧开始角度赋值为0 因为控制停留指定位置的角度计算是根据开始角度为0计算的 mStartSpanAngle = 0; isSpanEnd = true; }

具体实现牵涉到一些数学知识,可能讲述不太清楚,不过上代码就比较好了,直接看代码会更加清晰,代码中注释很详细,防止以后自己再回头看的时候忘记。欢迎访问github地址,查看完整代码,可以根据自己的需求去修改,顺便学习一下自定义view了解一下SurfaceView的用法。

地址:完整代码地址欢迎start,如有发现问题请多多指点互相学习交流。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-09-20 00:32:32

Android使用surfaceView自定义抽奖大转盘的相关文章

Android使用surfaceView自定义抽奖大转盘_Android

使用surfaceView自定义抽奖大转盘 话不多说,先上效果图 完整代码地址欢迎start 实现思路以及过程 1.首先了解SurfaceView的基本用法,它跟一般的View不太一样,采用的双缓存机制,可以在子线程中绘制View,不会因为绘制耗时而失去流畅性,这也是选择使用SurfaceView去自定义这个抽奖大转盘的原因,毕竟绘制这个转盘的盘块,奖项的图片和文字以及转动都是靠绘制出来的,是一个比较耗时的绘制过程. 2.使用SurfaceView的一般模板样式 一般会用到的成员变量 priva

jquery网页抽奖大转盘效果代码

大转盘原理:随机出一个数字,通过后台算出在那个概率区间返回指定跳转的角度 例 一等奖 概率1% 如果在1-100 随机出100则跳转一等奖的角度范围内 二等奖 概率2% 如果在1-100 随机出99-98则跳转二等奖的角度范围内 三等奖 概率97% 如果在1-100 随机出97-1则跳转三等奖的角度范围内  代码如下 复制代码 <!DOCTYPE html> <html><head><meta http-equiv="Content-Type"

Android中利用SurfaceView制作抽奖转盘的全流程攻略_Android

一.概述今天给大家带来SurfaceView的一个实战案例,话说自定义View也是各种写,一直没有写过SurfaceView,这个玩意是什么东西?什么时候用比较好呢? 可以看到SurfaceView也是继承了View,但是我们并不需要去实现它的draw方法来绘制自己,为什么呢? 因为它和View有一个很大的区别,View在UI线程去更新自己:而SurfaceView则在一个子线程中去更新自己:这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞. 知道

php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法

php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法.用法很简单,代码里有详细注释说明,一看就懂 <?php /* * 经典的概率算法, * $proArr是一个预先设置的数组, * 假设数组为:array(100,200,300,400), * 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内, * 如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间, * 在本例当中就是减去100,也就是说第二个数是在1,900这个范围内筛选的. * 这样 筛选到最终,总

使用jQuery Rotare实现微信大转盘抽奖功能_jquery

很多公司到了年底都会做一些抽奖活动来刺激.吸引.粘住客户,比如抽奖转盘活动. 前几天用一个jqueryRotate插件实现了转盘的效果.比起那些很炫丽的flash是稍逊点,但也基本实现了需求 效果图: 实现这个其实蛮简单的,转动的效果用的jqueryRotate插件,所以只要判断每个奖荐对应的角度,然后设置指针的转动角度就可以了.比如关键的是jqueryRotate这个插件的用法. jqueryRotate的资料: 支持Internet Explorer 6.0+ .Firefox 2.0 .S

基于PHP代码实现中奖概率算法可用于刮刮卡、大转盘等抽奖算法_php实例

大转盘中奖概率算法在我们的日常生活中,经常遇到,那么基于php代码是如何实现中奖概率算法的,下面通过一段代码实例给大家介绍php中奖概率算法,代码简单易懂,并且附有注释,具体代码如下所示: <?php /* * 经典的概率算法, * $proArr是一个预先设置的数组, * 假设数组为:array(100,200,300,400), * 开始是从1,1000 这个概率范围内筛选第一个数是否在他的出现概率范围之内, * 如果不在,则将概率空间,也就是k的值减去刚刚的那个数字的概率空间, * 在本例

js实现大转盘抽奖游戏实例_javascript技巧

本文实例讲述了js实现大转盘抽奖游戏.分享给大家供大家参考.具体实现方法如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <hea

Core Animation一些Demo总结 (动态切换图片、大转盘、图片折叠、进度条等动画效果)_Android

前一篇总结了Core Animation的一些基础知识,这一篇主要是Core Animation 的一些应用,涉及到CAShapeLayer.CAReplicatorLayer等图层的知识. 先看效果图: 1.切换图片: 2.彩票转盘 3.图片折叠 4.进度条旋转 5.粒子效果 一.切换图片 看起来很复杂的动画,通过少量的计算和编码就可以简单的实现.要做到这一步,必须是需要研究iOS开发中的Core Animation和Core Graphics框架的.日常工作中,对于很多东西不求甚解,只是拿过

jQuery实现大转盘抽奖活动仿QQ音乐代码分享_jquery

jQuery实现大转盘抽奖活动仿QQ音乐抽奖特效源码是一款基于jQuery,点击大转盘开始抽奖可抽到绿钻的仿qq音乐抽奖转盘的代码. 运行效果图:---------------------------------------效果查看 源码下载-------------------------------------- 为大家分享的jQuery实现大转盘抽奖活动仿QQ音乐抽奖特效代码如下 <head> <meta http-equiv="Content-Type" co