有個朋友需要寫個抽獎大轉(zhuǎn)盤的功能,就讓我?guī)兔懥讼?。我用?種方法實(shí)現(xiàn)了效果,在這里和大家一起分享下。
一、一鍵轉(zhuǎn)動大轉(zhuǎn)盤
我一開始拿到手的是一堆的圖片,然后自己花了點(diǎn)時間,搭建出美工要求的UI,接下來就開始分析如何讓它轉(zhuǎn)動了。如下圖:


首先,大家先到做旋轉(zhuǎn)的動畫,肯定是用到系統(tǒng)自帶的CABasicAnimation框架下面的方法,確實(shí)用這個做十分的方便,只需要我們設(shè)置相關(guān)屬性就可以搞定的。
可以看到上圖中,所有的獎勵是把大圓給八等分了,而中獎的指針是一直停留在正上面不變的,我們所改變的是轉(zhuǎn)盤和對應(yīng)的獎勵的位置。
那思路接下來是比較相對清晰了,我們只需要把角度也八等分,讓指針對準(zhǔn)每一個獎勵區(qū)域的中心即可。如果讓轉(zhuǎn)盤順時針旋轉(zhuǎn),那么第一個“500”對應(yīng)的是0°或者360°,左側(cè)“一束鮮花”對應(yīng)的則是45°,以此類推。我們事先可以把獎勵按這樣的順序放到數(shù)組中,0°對應(yīng)的是數(shù)組中第一個的獎勵,45°對應(yīng)的是第二個的獎勵......好了,思路有了,就可以直接寫代碼,邊寫邊調(diào)整了,下面我附上點(diǎn)擊“Go”之后的動畫效果代碼
-(void)startAnimaition
{
NSInteger turnAngle;//8個獎勵分別對應(yīng)的角度
NSInteger randomNum = arc4random()%100;//控制概率
NSInteger turnsNum = arc4random()%5+1;//控制圈數(shù)
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"];
// 轉(zhuǎn)盤結(jié)束后調(diào)用,顯示獲得的對應(yīng)獎勵
self.label.text = [NSString stringWithFormat:@"恭喜您抽中%@",self.labelText];
}
1.預(yù)先算好8個區(qū)域,區(qū)域中心每個對應(yīng)的角度(比如,“500”對應(yīng)的是0°和135°;“2000”對應(yīng)了135°)
2.用隨機(jī)數(shù) NSInteger randomNum = arc4random()%100; 來控制轉(zhuǎn)動事件的概率,如果你想讓“一束鮮花”的概率有20%,那么你可以給它設(shè)置隨機(jī)數(shù)20-40都停留在鮮花的區(qū)域(當(dāng)然也可以是30-50的數(shù)字啦)
3.因?yàn)轷r花有2個區(qū)域,為了都可以有機(jī)會停留,那么久20-30的時候,停留在第一塊鮮花的區(qū)域;30-40的時候,停留在第二塊鮮花的區(qū)域
4.你可以用一個隨機(jī)數(shù)控制轉(zhuǎn)動的圈數(shù) NSInteger turnsNum ,也可以定死多少圈
5.接下來直接上旋轉(zhuǎn)動畫的代碼,這里需要注意的是,我們在考慮問題或者看得時候,都是用角度來算的。而實(shí)際動畫中的屬性,是用弧度來算的。 1弧度=180/π度;1度=π/180弧度,自己可以換算下。
二、手動旋轉(zhuǎn)大轉(zhuǎn)盤

這個動畫,是捕捉到手指在屏幕上的起始點(diǎn)和重點(diǎn),然后計算讓轉(zhuǎn)盤跟著轉(zhuǎn)動。主要方法如下:
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
-(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
-(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
主要用了這三個觸摸屏幕相關(guān)的方法

需要注意,我們捕捉到的點(diǎn)是屏幕左上角為起始點(diǎn)的坐標(biāo),我們需要轉(zhuǎn)化成相對于圓心的坐標(biāo)
3.角度和弧度的轉(zhuǎn)換,依舊需要注意
extern float atan2f(float, float);
這個是C語言中的數(shù)學(xué)函數(shù)庫,意思是以弧度為單位計算并返回點(diǎn) y/x 的角度,該角度從圓的 x 軸(其中,0,0 表示圓心)沿逆時針方向測量
5,為了讓旋轉(zhuǎn)有快到慢,直至停止,所以需要每次都把旋轉(zhuǎn)的角度慢慢變小。
然后配合著我下面的代碼看吧:
- (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.捕捉起始點(diǎn)
//2.算出相對與轉(zhuǎn)盤中點(diǎn)的坐標(biāo)
//3.點(diǎn)(也就是坐標(biāo))轉(zhuǎn)換成弧度
//4.弧度轉(zhuǎn)換成角度
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);
//捕捉終點(diǎn)
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語言中的數(shù)學(xué)函數(shù)庫
//以弧度為單位計算并返回點(diǎn) y/x 的角度值
//該角度從圓的 x 軸(其中,0,0 表示圓心)沿逆時針方向測量
return atan2f(point.x, point.y);
}
//為了讓旋轉(zhuǎn)持續(xù)下去,并且越來越慢,每次的角度都是上一次啊的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的鏈接,有需要的同學(xué)可以下載來看看