iOS抽奖大转盘的二种实现方法

有个朋友需要写个抽奖大转盘的功能,就让我帮忙写了下。我用了2种方法实现了效果,在这里和大家一起分享下。

一、一键转动大转盘
我一开始拿到手的是一堆的图片,然后自己花了点时间,搭建出美工要求的UI,接下来就开始分析如何让它转动了。如下图:


demo1没转之前

demo1转动之后

首先,大家先到做旋转的动画,肯定是用到系统自带的CABasicAnimation框架下面的方法,确实用这个做十分的方便,只需要我们设置相关属性就可以搞定的。
可以看到上图中,所有的奖励是把大圆给八等分了,而中奖的指针是一直停留在正上面不变的,我们所改变的是转盘和对应的奖励的位置。
那思路接下来是比较相对清晰了,我们只需要把角度也八等分,让指针对准每一个奖励区域的中心即可。如果让转盘顺时针旋转,那么第一个“500”对应的是0°或者360°,左侧“一束鲜花”对应的则是45°,以此类推。我们事先可以把奖励按这样的顺序放到数组中,0°对应的是数组中第一个的奖励,45°对应的是第二个的奖励......好了,思路有了,就可以直接写代码,边写边调整了,下面我附上点击“Go”之后的动画效果代码

-(void)startAnimaition
{
    NSInteger turnAngle;//8个奖励分别对应的角度
    NSInteger randomNum = arc4random()%100;//控制概率
    NSInteger turnsNum = arc4random()%5+1;//控制圈数
    
    if (randomNum>=0 && randomNum<20) {//80%的概率 就是0-80
        
        if (randomNum < 10) {
            turnAngle = 0;
        }else{
            turnAngle = 135;
        }
        self.labelText = self.turntable.numberArray[0];
        NSLog(@"抽中了500");
        
    } else if (randomNum>=20 && randomNum<40) {
        
        if (randomNum < 35) {
            turnAngle = 45;
        }else{
            turnAngle = 225;
        }
        self.labelText = self.turntable.numberArray[3];
        NSLog(@"抽中了鲜花");
        
    } else if (randomNum >=40 && randomNum<60) {
        
        turnAngle = 315;
        self.labelText = self.turntable.numberArray[1];
        NSLog(@"抽中了2000");
        
    } else if(randomNum >=60 && randomNum<80){
        
        if (randomNum < 75) {
            turnAngle = 90;
        }else{
            turnAngle = 270;
        }
        self.labelText = self.turntable.numberArray[2];
        NSLog(@"抽中了5000");
        
    }else{
        
        turnAngle = 180;
        self.labelText = self.turntable.numberArray[4];
        NSLog(@"抽中了20000");
    }
    
    CGFloat perAngle = M_PI/180.0;
    
    CABasicAnimation* rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = [NSNumber numberWithFloat:turnAngle * perAngle + 360 * perAngle * turnsNum];
    rotationAnimation.duration = 3.0f;
    rotationAnimation.cumulative = YES;
    rotationAnimation.delegate = self;
    //由快变慢
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    rotationAnimation.fillMode=kCAFillModeForwards;
    rotationAnimation.removedOnCompletion = NO;
    [self.turntable.rotateWheel.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
    
    // 转盘结束后调用,显示获得的对应奖励
    self.label.text = [NSString stringWithFormat:@"恭喜您抽中%@",self.labelText];
    
}

1.预先算好8个区域,区域中心每个对应的角度(比如,“500”对应的是0°和135°;“2000”对应了135°)
2.用随机数 NSInteger randomNum = arc4random()%100; 来控制转动事件的概率,如果你想让“一束鲜花”的概率有20%,那么你可以给它设置随机数20-40都停留在鲜花的区域(当然也可以是30-50的数字啦)
3.因为鲜花有2个区域,为了都可以有机会停留,那么久20-30的时候,停留在第一块鲜花的区域;30-40的时候,停留在第二块鲜花的区域
4.你可以用一个随机数控制转动的圈数 NSInteger turnsNum ,也可以定死多少圈
5.接下来直接上旋转动画的代码,这里需要注意的是,我们在考虑问题或者看得时候,都是用角度来算的。而实际动画中的属性,是用弧度来算的。 1弧度=180/π度;1度=π/180弧度,自己可以换算下。

二、手动旋转大转盘

手指滑动旋转屏幕

这个动画,是捕捉到手指在屏幕上的起始点和重点,然后计算让转盘跟着转动。主要方法如下:

 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
 -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
 -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event

主要用了这三个触摸屏幕相关的方法

小弟不才,有点丑

需要注意,我们捕捉到的点是屏幕左上角为起始点的坐标,我们需要转化成相对于圆心的坐标
3.角度和弧度的转换,依旧需要注意

extern float atan2f(float, float);

这个是C语言中的数学函数库,意思是以弧度为单位计算并返回点 y/x 的角度,该角度从圆的 x 轴(其中,0,0 表示圆心)沿逆时针方向测量
5,为了让旋转有快到慢,直至停止,所以需要每次都把旋转的角度慢慢变小。

然后配合着我下面的代码看吧:

- (void)viewDidLoad
{
    _updateEnable = NO;
    _angle = 0;
    
    [super viewDidLoad];
    
    self.view.backgroundColor = [UIColor whiteColor];
    _turntable = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, screenW-50, screenW-50)];
    _turntable.image = [UIImage imageNamed:@"turntable.jpeg"];
    _turntable.center = self.view.center;
    [self.view addSubview:_turntable];
    
    //将NSTimer添加到NSRunloop
    NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
    _timer =[ NSTimer timerWithTimeInterval:1.0f/60 target:self selector:@selector(updateMyAngle) userInfo:nil repeats:YES];
    [runLoop addTimer:_timer forMode:NSDefaultRunLoopMode];
    
    
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    _updateEnable = NO;
    _angle = 0;
}


-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    UITouch *touch = [touches anyObject];
    
    //1.捕捉起始点
    //2.算出相对与转盘中点的坐标
    //3.点(也就是坐标)转换成弧度
    //4.弧度转换成角度
    CGPoint previousLocation = [touch previousLocationInView:touch.view];
    CGPoint previousPoint = [self relativePoint:previousLocation and:_turntable.center];
    CGFloat previousVector = [self toAngle:previousPoint];
    CGFloat previousDrgress = RADIAN_TO_DEGREE(previousVector);
    
    //捕捉终点
    CGPoint nowLocation = [touch locationInView:touch.view];
    CGPoint nowPoint = [self relativePoint:nowLocation and:_turntable.center];
    CGFloat nowVector = [self toAngle:nowPoint];
    CGFloat nowDrgress = RADIAN_TO_DEGREE(nowVector);
    
    //得出相对角度
    _angle = -(nowDrgress - previousDrgress);
    NSLog(@"angle = %f",_angle);
    [self setRotate:_angle];
    
}
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    _updateEnable = YES;
}

- (void)setRotate:(CGFloat)degress
{
    CGFloat rotate = DEGREE_TO_RADIAN(degress);
    
    CGAffineTransform transform = _turntable.transform;
    transform = CGAffineTransformRotate(transform, rotate);
    _turntable.transform = transform;
    
}

- (CGPoint)relativePoint:(CGPoint)point1 and:(CGPoint)point2
{
    CGPoint point;
    point.x = point1.x - point2.x;
    point.y = point1.y - point2.y;
    
    return point;
}


- (float)toAngle:(CGPoint)point
{
    //是C语言中的数学函数库
    //以弧度为单位计算并返回点 y/x 的角度值
    //该角度从圆的 x 轴(其中,0,0 表示圆心)沿逆时针方向测量
    return atan2f(point.x, point.y);
}

//为了让旋转持续下去,并且越来越慢,每次的角度都是上一次啊的0.99
- (void)updateMyAngle
{
    if(_updateEnable)
    {
        if(fabs(_angle)>1)
        {
            [self setRotate:_angle];
            _angle = 0.99 * _angle;
        }
        else
        {
            _angle = 0;
        }
    }
}

https://github.com/dongjueai/YDXTurntable
这个是demo的链接,有需要的同学可以下载来看看

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容