2

Android SurfaceView实战 打造抽奖转盘

 3 years ago
source link: https://blog.csdn.net/lmj623565791/article/details/41722441
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Android SurfaceView实战 打造抽奖转盘

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/41722441 ,本文出自:【张鸿洋的博客】

今天给大家带来SurfaceView的一个实战案例,话说自定义View也是各种写,一直没有写过SurfaceView,这个玩意是什么东西?什么时候用比较好呢?

可以看到SurfaceView也是继承了View,但是我们并不需要去实现它的draw方法来绘制自己,为什么呢?

因为它和View有一个很大的区别,View在UI线程去更新自己;而SurfaceView则在一个子线程中去更新自己;这也显示出了它的优势,当制作游戏等需要不断刷新View时,因为是在子线程,避免了对UI线程的阻塞。

知道了优势以后,你会想那么不使用draw方法,哪来的canvas使用呢?

大家都记得更新View的时候draw方法提供了一个canvas,SurfaceView内部内嵌了一个专门用于绘制的Surface,而这个Surface中包含一个Canvas。

有了Canvas,我们如何获取呢?

SurfaceView里面有个getHolder方法,我们可以获取一个SurfaceHolder。通过SurfaceHolder可以监听SurfaceView的生命周期以及获取Canvas对象。

2、一般的写法

综上所述,一般SurfaceView类中我们会这么写代码:

结合上面我们的介绍,我们在构造中通过getHolder拿到SurfaceHolder对象,然后设置一个addCallback回调,去监听SurfaceView的生命周期,生命周期有三个方法,分别为create,change,destory;我们一般在create里面进行初始化的一些操作,然后开启线程;在destroy里面设置关闭线程;

所有的绘制流程都是线程的run方法里面,可以看到我们的draw方法。

注意下,我们在draw里面进行了try catch然后很多的判空,主要是因为,当用户点击back或者按下home键以后,surfaceview会被销毁;

 mHolder.lockCanvas();返回的就是null了,所以为了避免造成空指针错误,我们各种判null,甚至还加了个try catch。

说了这么多,竟然没看到效果图,这怎么能行~~

3、效果图

就这么个效果,当然了模拟器录制的效果肯定没有真机上效果流畅。

结合上面我们给出的模版,我们需要改变的就是,在create回调里面需要去初始化一些变量,在draw方法里面去绘制我们的文本、图片、扇形块块等等。整体架构没有变化。

4、转盘的制作

1、构造方法以及变量

我们在构造中设置了Callback回调,然后通过成员变量,大家应该也能看得出来每个变量的作用,以及可能有的代码快。

2、onMeasure

这里我简单重写了一下onMeasure,使我们的控件为正方形

并且为我们的mRadius和mCenter进行了赋值。

3、surfaceCreated

surfaceCreated我们初始化了绘制需要用到的变量,以及开启了线程。

surfaceDestroyed中就一行代码,顺便贴出。

可以猜到核心的代码都在我们的线程的run里面了。

4、draw

可以看到我们的run里面调用了draw,和上面模版一致。

使用通过 mHolder.lockCanvas();获得我们的Canvas,然后就可以尽情的绘制了。

1、绘制背景drawBg();

这个比较简单,其实就是绘制一个棕色的圆盘,在运行代码前,你可以忽略掉,不影响。

接下来一个for循环,且角度每次递增(360 / mItemCount);就是绘制每个盘块以及盘块上的字体和图标了。

2、绘制盘块

这个比较简单了~~

3、绘制文本

利用Path,添加入一个Arc,然后设置水平和垂直的偏移量,垂直偏移量就是当前Arc朝着圆心移动的距离;水平偏移量,就是顺时针去旋转,

我们偏移了 (mRadius * Math.PI / mItemCount / 2 - textWidth / 2);目的是为了文字居中。mRadius * Math.PI 是圆的周长;周长/ mItemCount / 2 是每个Arc的一半的长度;

拿Arc一半的长度减去textWidth / 2,就把文字设置居中了。

最后,用过path去绘制文本即可。

凑合看个图:

本来字的位置在外围的横线处,我们希望到内部的横线位置,需要调节水平和垂直的偏移;水平和垂直的平移方向为绿色的箭头;大概就这样。

4、绘制图像

绘制图片主要就是图片的中心的确定,这里我们固定图片大小为直径的1/8;至于圆心的确定,看下图:

我们需要图片的中心,为每个块块的中间:

我们希望图片在中间的那个点,点距离圆心即center的距离为r = mRadius /2 / 2 ;

绿线与水平线的夹角为a = 360 / count / 2 ,本图为30 ;

于是那个点的坐标为:(mCenter + r * cos a , mCenter + r * sina );

其他的点同理,唯一变化就是a 的角度 ,在计算时需要把a转化为弧度制。

 集合图和上面的代码好好理解下。

到此基本我们的圆盘就绘制好了。

5、让圆盘先滚一会

怎么让圆盘滚动呢?如果你足够细心,应该发现我们的draw里面有这么一句:

mStartAngle += mSpeed;

其实每次draw都会让mStartAngle += mSpeed;看起来就是滚动了。

那么滚动,其实就是去设置mSpeed即可。

嗯,是的,如果单纯想滚动,只要去设置mSpeed就行了;但是,这样就行了么,就拿我们这个奖项来说,你敢1/6的概率拿到大奖么,你个IT公司让人抽到妹子一只咋办。

所以我们还要来控制用户抽奖的概率,这里我们让用户中奖的产品在开始滚的时候就决定了。是不是玩转盘的时候很傻很天真,以为可以中大奖。

当外部调用luckyStart即可以旋转,index为停下来的位置,水平位置开始算,即0为相机,1为IPAD。

这里又开始牵扯数学了:

这个from , to 比较简单,就是确定中将范围,比如我index=0,则只要转了210-270之间,我们的相机都会被垂直向上的指针指向。

那么这个targetFrom是干嘛的,是决定你点击停止的时候转多长距离,这里我们设置为4圈多一点,这个多一点就是上面的from和to。

最麻烦就是v1的计算了,既然我们希望决定停下里的位置,那么这个速度就是我们去计算出来的,怎么算呢?

我们旋转的距离有了targetFrom,然后我们点击的时候mSpeed -= 1;也就是说速度是递减的,每次减去1。

递减说明是个等差数列,等差数列的和是targetFrom。

等差数列的求和公式大家记得否:(首项+末项)*(项数)/ 2

我们的首项是v1 ,末项肯定是0 , 项数 (v1/ 1 + 1)加个1为向上进一位。 

那么式子就是: (v1 + 0 ) * (v1 / 1 +1) /2 = targetFrom ; 只有v1是未知数,一元二次方程的解,大家还记得否,不记得我来写 : 

于是我们的v1就是v1=-1+(1*1 + 8 *1 * target)/2;

好了,尼玛求出来v1,为啥我们代码还有个v2,这是因为v1停下来永远在某个块块的边界,我们屌丝又不傻,你每次停一个位置,都知道你造假。

那么我们就求个v2,这个停下块块的最后位置。

最后我们的速度为v1,v2间的一个随机数,也就是在某个块块中间任意位置。这样就可以让你觉得每次都在这个块块,但是指针位置还不同。

好了,这里就是最复杂的地方了,如果你比较善良,不想内置这个功能,那就随便设置个速度吧。

6、让圆盘停止滚动

别忘了,我们5计算那么多,都是从水平那个距离为0开始计算的,于是我们的停止代码是这样的:

最后贴出我们的主布局文件和Activity

7、布局文件和MainActivity

终于写完了,数学把我这类渣渣计算的不行不行的。ps:抠图真恶心,爱歌撒时候给我传递些艺术的造诣和ps的技术呢。。。。

好了,我们的按钮是用布局文件加上的,方便大家自己定制按钮~~~并且大家的奖项,颜色,以及图片可以自己定义,这个不用说了吧,修改count,以及那几个数组就行。

有可能的话,还会写一篇SurfaceView做游戏的博文,不过案例可能会在网上进行寻找,哈。

源码点击下载

发现任何bug欢迎留言。

----------------------------------------------------------------------------------------------------------

博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

1、Android 自定义控件实战 电商活动中的刮刮卡

2、Android自定义控件实战  打造Android流式布局和热门标签

3、Android智能机器人“小慕”的实现

4、高仿QQ5.0侧滑

5、高仿微信5.2.1主界面及消息提醒


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK