美文网首页iOS1开开心心写代码iOS Developer
iOS抽奖大转盘的二种实现方法

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

作者: 干不动 | 来源:发表于2016-11-28 10:27 被阅读4612次

    有个朋友需要写个抽奖大转盘的功能,就让我帮忙写了下。我用了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的链接,有需要的同学可以下载来看看

    相关文章

      网友评论

      • cd8944436c66:我发现可以一直点啊,在点击GO按钮的时候,结果就出来了。但是转盘在转的时候,还可以点击。当转盘动起来的时候,怎么屏蔽点击事件。
      • 啊世ka:怎么在uiview 初始化里面自定义奖品名称?
      • 我不是掌柜: override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        //抽奖盘
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDelegate(self)
        UIView.setAnimationDuration(0.1)
        imageView.transform = CGAffineTransform.init(rotationAngle: CGFloat(Double.pi/2))
        UIView.setAnimationDidStop(#selector(ViewController.animationEnd))
        UIView.commitAnimations()

        }
        func animationEnd() {
        UIView.beginAnimations(nil, context: nil)
        UIView.setAnimationDelegate(self)
        UIView.setAnimationCurve(UIViewAnimationCurve.linear)
        UIView.setAnimationDuration(0.1)
        index = index + 1
        imageView.transform = CGAffineTransform.init(rotationAngle: CGFloat(Double(index)*Double.pi/2))
        UIView.setAnimationDidStop(#selector(ViewController.animationEnd))

        UIView.commitAnimations()
        }
      • sun_dev:你好,我们有个需求是先保持轮盘 慢转,点击抽奖后 开始加速 然后停止;请教一下作者,你有什么思路吗?
        我不是掌柜:setAnimationCurve就行了把
      • 帅狗黑皮668:不赖不赖
      • 阿尔法代码狗:概率你是怎么样设置的呢,楼主
        董小白:楼主,你好,非常感谢你提供的思路,帮上我很大的忙。我有一个小问题,就是查看你的项目里面,有这一句代码UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0,M_PI * CGRectGetHeight(self.bounds)/8,CGRectGetHeight(self.bounds)/2)];里面的M_PI * CGRectGetHeight(self.bounds)/8我没有看懂这是怎么计算的。小白一枚,请赐教!
        阿尔法代码狗:@姚兜兜 多谢,ok了,
        干不动:@阿尔法代码狗 如果你可以控制角度的话,控制概率并不难,你可以用一个100以内的随机数来控制概率。比如随机数0-20,你可以让它停在某一块区域,这样概率就是20%

      本文标题:iOS抽奖大转盘的二种实现方法

      本文链接:https://www.haomeiwen.com/subject/phdgpttx.html