iOS开发核心动画之星座幸运转盘

摘要:
1、 星座转盘1.示意图2.设计思路每个星座条是一个UIButton,设置按钮的宽度和高度,将位置点设置在整个转盘的中点,然后通过anchorPoint(0.5,1)将每个按钮上的图像定位在位置点,通过截取图像获得图像3.代码1˃通过xib描述转盘底座,将其关联到新创建的View类(LDWheelView.h),并在View中加载xib以初始化+(instancetype)wheel{

一. 星座转盘

1. 示意图

iOS开发核心动画之星座幸运转盘第1张 

2. 设计思路

    每一个星座条是一个UIButton,设置按钮的宽高,设置position点在整个转盘的中点,再通过anchorPoint(0.5, 1)定位到position点

    每一个按钮上的图片通过截取图片获取


3. 代码

1> 通过一个xib描述转盘底座,关联到一个新创建的View类(LDWheelView.h),在View中加载xib进行初始化

  1. + (instancetype)wheel
  2. {
  3. return [[self alloc] init];
  4. }
  5. - (instancetype)initWithFrame:(CGRect)frame
  6. {
  7. if (self = [super initWithFrame:frame]) {
  8. self = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([LDWheelView class]) owner:nil options:nil] lastObject];
  9. }
  10. return self;
  11. }
  12. - (void)awakeFromNib
  13. {
  14. // 创建按钮
  15. [self setupBtn];
  16. }

2> 初始化过程中创建12星座按钮,并设置按钮tag

  1. - (void)setupBtn
  2. {
  3. // wheelImageV允许和用户互动
  4. self.wheelImageV.userInteractionEnabled = YES;
  5. CGFloat btnW = 68;
  6. CGFloat btnH = 143;
  7. CGFloat angle = 0;
  8. // 0.加载图片
  9. UIImage *imageNor = [UIImage imageNamed:@"LuckyAstrology"];
  10. UIImage *imageSel = [UIImage imageNamed:@"LuckyAstrologyPressed"];
  11. // 加载图片时只能加载圈1X倍的图片,而屏幕显示时圈2X倍的图片,根据屏幕计算出要倍数
  12. CGFloat scale = [UIScreen mainScreen].scale;
  13. CGFloat cutImageW = imageNor.size.width / 12 * scale;
  14. CGFloat cutImageH = imageNor.size.height *scale;
  15. for (int i = 0; i < 12; ++i) {
  16. // 1.创建按钮
  17. LDWheelBtn *btn = [LDWheelBtn buttonWithType:UIButtonTypeCustom];
  18. btn.tag = i;
  19. // 2.设置选中背景色
  20. [btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
  21. // 3.设置位置和尺寸
  22. btn.bounds = CGRectMake(0, 0, btnW, btnH);
  23. btn.layer.anchorPoint = CGPointMake(0.5, 1);
  24. btn.layer.position = CGPointMake(self.wheelImageV.bounds.size.width * 0.5, self.wheelImageV.bounds.size.width * 0.5);
  25. // 4.旋转角度
  26. btn.transform = CGAffineTransformMakeRotation(angle / 180.0 * M_PI);
  27. // 每创建一个按钮旋转角度增加30
  28. angle += 30;
  29. // 5.设置图片
  30. CGImageRef imageRefNor = CGImageCreateWithImageInRect(imageNor.CGImage, CGRectMake(i * cutImageW, 0, cutImageW, cutImageH));
  31. CGImageRef imageRefSel = CGImageCreateWithImageInRect(imageSel.CGImage, CGRectMake(i * cutImageW, 0, cutImageW, cutImageH));
  32. [btn setImage:[UIImage imageWithCGImage:imageRefNor] forState:UIControlStateNormal];
  33. [btn setImage:[UIImage imageWithCGImage:imageRefSel] forState:UIControlStateSelected];
  34. // 5.添加到wheelImageV上
  35. [self.wheelImageV addSubview:btn];
  36. // 6.监听按钮
  37. [btn addTarget:self action:@selector(setSelect:) forControlEvents:UIControlEventTouchUpInside];
  38. if (i == 0) {
  39. [self setSelect:btn];
  40. }
  41. }
  42. }

注:扣取一张图片中某个位置为新图片

. 加载图片

  1. UIImage *imageNor = [UIImage imageNamed:@"LuckyAstrology"];

加载图片时只能加载圈1X倍的图片,而屏幕显示时圈2X倍的图片,根据屏幕计算出要倍数

  1. CGFloat scale = [UIScreen mainScreen].scale;

. 根据屏幕的倍数x原始图片的宽度/高度 ➗ 12 算出扣取图片的宽高

  1. CGFloat cutImageW = imageNor.size.width / 12 * scale;
  2. CGFloat cutImageH = imageNor.size.height *scale;

. 扣取图片 CGImageCreateWithImageInRect 方法

  1. CGImageRef imageRefNor = CGImageCreateWithImageInRect(imageNor.CGImage, CGRectMake(i * cutImageW, 0, cutImageW, cutImageH));

3> 设置选中按钮, 在初始化过程中创建按钮并监听按钮,现在实现监听方法

定义按钮属性记录上一个按钮

  1. /** 记录上一个按钮 */
  2. @property (nonatomic, weak) LDWheelBtn *preBtn;

实现监听方法:

. 将上一个按钮selected设置为NO

. 将当前按钮selected设置为YES

. 将当前按钮赋值给上一个按钮

  1. - (void)setSelect:(LDWheelBtn *)btn
  2. {
  3. // 1.设置上一个按钮selected为NO
  4. self.preBtn.selected = NO;
  5. // 2.设置当前按钮selected为YES
  6. btn.selected = YES;
  7. // 3.将当前按钮赋值给上一个按钮
  8. self.preBtn = btn;
  9. }

4> 由于点击按钮不需要高亮状态,所以就需要自定义按钮重写设置按钮高亮方法

. 自定义按钮创建一个类(LDWheelBtn.h)继承UIButton

  1. // 取消按钮高亮状态
  2. - (void)setHighlighted:(BOOL)highlighted
  3. {
  4. }

. 重置按钮上图片的位置和尺寸

  1. //返回按钮当中图片的尺寸位置.
  2. //contentRect:当前按钮的尺寸位置 .
  3. - (CGRect)imageRectForContentRect:(CGRect)contentRect{
  4. CGFloat btnW = 40;
  5. CGFloat btnH = 50;
  6. CGFloat btnX = (contentRect.size.width - btnW) * 0.5;
  7. CGFloat btnY = 25;
  8. return CGRectMake(btnX, btnY, btnW, btnH);
  9. }

. 由于按钮是旋转的就有一些重叠,重叠部分会影响点击,因此要在自定义按钮上拦截事件响应

用一种取巧的方法,让按钮重叠部分不能响应事件,即设置一个区域(未重叠区域)才能响应事件

,重写按钮的hitText方法来判定

  1. -(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
  2. CGRect rect = CGRectMake(0, 0, self.bounds.size.width, 50);
  3. if (CGRectContainsPoint(rect, point)) {
  4. return [super hitTest:point withEvent:event];
  5. }else{
  6. return nil;
  7. }
  8. }

5> 在控制器中点击开始按钮转盘开始转动,调用WheelView中提供的开始转动方法

. 开始转动将定时器的paused属性设置为NO,设置为YES为暂停动画

  1. //开始旋转
  2. - (void)start
  3. {
  4. self.link.paused = NO;
  5. }

. 定义定时器属性

  1. /** 定时器.*/
  2. @property (nonatomic ,weak) CADisplayLink *link;

. 懒加载创建定时器(CADisplayLink 这个定时器1s刷新60次)

  1. -(CADisplayLink *)link{
  2. if (_link == nil) {
  3. //添加定时器.
  4. CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)];
  5. [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
  6. _link = link;
  7. }
  8. return _link;
  9. }

. 实现定时器监听方法,将转盘旋转(UIView旋转)

  1. - (void)update{
  2. //让转盘开始旋转
  3. self.contentView.transform = CGAffineTransformRotate(self.contentView.transform, M_PI / 250.0);
  4. }

6> 选择一个星座,点击中间的开始选号,当转盘停止旋转时,星座指针指向正上方

. 点击开始选号,创建基本动画,将转盘旋转N圈

  1. //开始选号
  2. - (IBAction)chooseNum:(id)sender {
  3. //创建动画对象
  4. CABasicAnimation *anim = [CABasicAnimation animation];
  5. //设置动画的属性值
  6. anim.keyPath = @"transform.rotation";
  7. anim.toValue = @(M_PI * 4);
  8. anim.delegate = self;
  9. anim.duration = 0.5;
  10. [self.contentView.layer addAnimation:anim forKey:nil];
  11. }

. 实现动画停止后的方法,来将指针回转到正上方

  1. //当动画结束时调用.
  2. -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
  3. //动画结束时,选择按钮指向最上方.
  4. //动画结束时,让选中的按钮倒着旋转回去.
  5. CGAffineTransform transform = self.preBtn.transform;
  6. CGFloat angle = atan2(transform.b, transform.a);
  7. self.contentView.transform = CGAffineTransformMakeRotation(-angle);
  8. }


免责声明:文章转载自《iOS开发核心动画之星座幸运转盘》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇树莓派3B+(一)【使用 DOM】理解 DOM下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

单选按钮(radio)的取值和点击事件

笔记走一波:获取单选按钮(radio)的选中值,以及它的点击事件的实现 首先要引入Jquery <script type="text/javascript" src="js/jquery-3.1.1.min.js"> 下面是一个简单的表单 <!-- 单选按钮的取值和点击事件--> <form action="#" metho...

在VB语言中,DOEVENTS的具体的用法和含义

DoEvents的应用及注意事项 转让控制权,以便让操作系统处理其它的事件。DoEvents 函数会返回一个 Integer,以代表 Visual Basic 独立版本中打开的窗体数目,例如,Visual Basic,专业版,在其它的应用程序中,DoEvents 返回 0。DoEvents 会将控制权传给操作系统。当操作系统处理完队列中的事件,并且在 Se...

Unity3d—GUI按钮控件

这是自己的第一篇记录自己的技术文章,自己还是个菜鸟,有错误之处还望大家能够多多指点。1、在project视图中创建C#脚本,我命名为 Gui_test 2、然后打开该脚本,输入以下代码:1 usingSystem.Collections; 2 usingSystem.Collections.Generic; 3 usingUnityEngine; 4...

Delphi Application.MessageBox详解

引数:1. Text:要显示的讯息2. Caption:讯息视窗的标题列文字3. Flags:讯息旗标3.1. 可指定讯息视窗上的图示3.2. 可指定讯息视窗出现的按钮3.3. 可指定预设Focus在哪一个按钮3.4. 可指定是否 Modal3.5. 其他引数说明:Text、Caption 引数为 PCahr 型态,字串型态的变数可用 PChar()转换,...

自定义JS控件-简单示例

1、  业务需求: 制作 一个按钮对象,然后 像 winfrom  那样调用 就可以了: 首先 我们新建一个 MyControls的 JS文件:(插入如下代码) //这里运用的面向对象的思想 ,新建了一个按钮对象 var button = function (ClientId) { this.control = null;...

安卓开发学习日记 DAY5——监听事件onClick的实现方法

今天主要学习了监听事件的是实现方法,就是说,做了某些动作后,怎么监听这个动作并作出相应反应。 方法主要有三种: 1.匿名内部类的方法 2.独立类的方法 3.类似实现接口的方法 以下分别分析: 1.匿名内部类的方法 就是使用innerClass的方式创建监听事件 步骤如下: 1)创建一个button,在xml中拖入一个button即可 2)在源程序中对but...