iOS版大轉盤
使用iOS內建的 CABasicAnimation 動畫簡單實現 一、核心代碼:
// 旋轉動畫 CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; // 開始位置 [anim setFromValue:[NSNumber numberWithFloat:0]]; // 結束 [anim setToValue:[NSNumber numberWithFloat:M_PI * 2.97]]; anim.duration = 5.0; // 動畫結束不要回到開始位置 anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; [anim setDelegate:self]; // 模式:先加速後減速 [anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; [imageView.layer addAnimation:anim forKey:@"rotation"];
旋轉的時候,M_PI 為半圈,M_PI * 2 為一圈;
轉盤等比平分,比如 items = 7;
從伺服器得到停止位置,比如 resultItem = 3;
算出停止的角度為 orign = resultItem / items * 2 * M_PI;
核心就醬紫,在此基礎上擴充下 二、擴充
.h
//// ViewController.h// demo//// Created by zhangwb on 15/7/22.// Copyright (c) 2015年 lxmy. All rights reserved.//#import <UIKit/UIKit.h>@interface ViewController : UIViewController/** 旋轉的位置 */@property (nonatomic, strong) UISegmentedControl *segmentedItem;/** 旋轉的方向 */@property (nonatomic, strong) UISegmentedControl *segmentedDirection;/** 提示文本 */@property (nonatomic, strong) UILabel *lblResult;/** 底盤 */@property (nonatomic, strong) UIImageView *imgRound;/** 指標 */@property (nonatomic, strong) UIButton *btnIndex;@end
.m
//// ViewController.m// demo//// Created by zhangwb on 15/7/22.// Copyright (c) 2015年 lxmy. All rights reserved.//// 大轉盤的例子//#import "ViewController.h"#import "Masonry.h"const static CGFloat ANIM_TIME = 5.0; // 動畫時間const static CGFloat ROTATION_EXTEND = 20; // 旋轉圈數延長 // 2 * M_PI = 1圈const static NSInteger ITEM_COUNT = 14; // 轉盤等比分割@interface ViewController () { UIAlertView *alert; Boolean isCW; // 是否順時針 float random; // 位置,demo中從0開始 float orign; // 角度}@end@implementation ViewController- (void)viewDidLoad { [super viewDidLoad]; [self addView];}- (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning];}/** 添加控制項 */- (void) addView { if ([self respondsToSelector:@selector(edgesForExtendedLayout)]) { self.edgesForExtendedLayout = UIRectEdgeNone; } self.title = @"大轉盤"; NSArray *arrayItem = [[NSArray alloc]initWithObjects:@"指標旋轉", @"底盤旋轉",nil]; _segmentedItem = [[UISegmentedControl alloc]initWithItems:arrayItem]; _segmentedItem.selectedSegmentIndex = 0; [_segmentedItem addTarget:self action:@selector(segmentedValueChanged) forControlEvents:UIControlEventValueChanged]; _segmentedItem.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_segmentedItem]; NSArray *arrayDirection = [[NSArray alloc]initWithObjects:@"逆時針", @"順時針", nil]; _segmentedDirection = [[UISegmentedControl alloc]initWithItems:arrayDirection]; _segmentedDirection.selectedSegmentIndex = 0; [_segmentedDirection addTarget:self action:@selector(segmentedDirectionValueChanged) forControlEvents:UIControlEventValueChanged]; _segmentedDirection.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_segmentedDirection]; _lblResult = [UILabel new]; _lblResult.textAlignment = NSTextAlignmentCenter; _lblResult.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_lblResult]; _imgRound = [UIImageView new]; _imgRound.image = [UIImage imageNamed:@"round"]; _imgRound.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_imgRound]; _btnIndex = [UIButton buttonWithType:UIButtonTypeCustom]; [_btnIndex setImage:[UIImage imageNamed:@"start"] forState:UIControlStateNormal]; [_btnIndex addTarget:self action:@selector(btnIndexClick) forControlEvents:UIControlEventTouchUpInside]; _btnIndex.translatesAutoresizingMaskIntoConstraints = NO; [self.view addSubview:_btnIndex]; int padding = 10; [_segmentedItem mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(self.view.mas_top).offset(padding * 5); make.centerX.equalTo(self.view.mas_centerX); }]; [_segmentedDirection mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(_segmentedItem.mas_bottom).offset(padding); make.centerX.equalTo(self.view.mas_centerX); }]; [_lblResult mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(_segmentedDirection.mas_bottom).offset(padding); make.centerX.equalTo(self.view.mas_centerX); make.height.mas_equalTo(25); }]; [_imgRound mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(_lblResult.mas_bottom).offset(padding * 2); make.centerX.equalTo(self.view.mas_centerX); }]; [_btnIndex mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(_imgRound); }];}/** 改變選擇位置 */- (void) segmentedValueChanged { orign = 0.0; _lblResult.text = @""; [_btnIndex.imageView.layer removeAllAnimations]; [_imgRound.layer removeAllAnimations]; _btnIndex.imageView.transform = CGAffineTransformMakeRotation(0); _imgRound.transform = CGAffineTransformMakeRotation(0);}/** 改變選擇方向 */- (void) segmentedDirectionValueChanged { isCW = _segmentedDirection.selectedSegmentIndex == 1; [self segmentedValueChanged];}/** 點擊事件 */- (void) btnIndexClick { _btnIndex.userInteractionEnabled = NO; [self getResult];}/** 類比從伺服器請求結果 */- (void) getResult { // 產生隨機數,作為停止項 // 這裡從0開始 0-ITEM_COUNT-1 random = (arc4random() % ITEM_COUNT); _lblResult.text = [NSString stringWithFormat:@"停止項=%.0lf", random]; if (_segmentedItem.selectedSegmentIndex == 0) { [self beginIndexRotate]; } else { [self beginRoundRotate]; }}/** 開始旋轉-指標 */- (void) beginIndexRotate { CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; if (isCW) { [anim setFromValue:[NSNumber numberWithFloat:M_PI * orign]]; orign = random / ITEM_COUNT * 2; [anim setToValue:[NSNumber numberWithFloat:M_PI * (ROTATION_EXTEND + orign)]]; } else { [anim setFromValue:[NSNumber numberWithFloat:-M_PI * orign]]; orign = 2 - random / ITEM_COUNT * 2; [anim setToValue:[NSNumber numberWithFloat:-M_PI * (ROTATION_EXTEND + orign)]]; } anim.duration = ANIM_TIME; anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; [anim setDelegate:self]; [anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; [_btnIndex.imageView.layer addAnimation:anim forKey:@"rotation"];}/** 開始旋轉-底盤 */- (void) beginRoundRotate { CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; if (isCW) { [anim setFromValue:[NSNumber numberWithFloat:M_PI * orign]]; orign = 2 - random / ITEM_COUNT * 2; [anim setToValue:[NSNumber numberWithFloat:M_PI * (ROTATION_EXTEND + orign)]]; } else { [anim setFromValue:[NSNumber numberWithFloat:-M_PI * orign]]; orign = random / ITEM_COUNT * 2; [anim setToValue:[NSNumber numberWithFloat:-M_PI * (ROTATION_EXTEND + orign)]]; } anim.duration = ANIM_TIME; anim.removedOnCompletion = NO; anim.fillMode = kCAFillModeForwards; [anim setDelegate:self]; [anim setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; [_imgRound.layer addAnimation:anim forKey:@"rotation"];}/** 動畫開始 */- (void)animationDidStart:(CAAnimation *)anim { _btnIndex.userInteractionEnabled = NO; _segmentedItem.userInteractionEnabled = NO; _segmentedDirection.userInteractionEnabled = NO;}/** 動畫結束 */- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { _btnIndex.userInteractionEnabled = YES; _segmentedItem.userInteractionEnabled = YES; _segmentedDirection.userInteractionEnabled = YES; if (!alert) { alert = [[UIAlertView alloc]initWithTitle:nil message:@"" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil]; } alert.message = [NSString stringWithFormat:@"你抽中%.0lf", random]; [alert show];}@end
看下效果
三、其它存在問題:
demo中轉盤是在拿到類比資料後開始轉動的,這樣很容易控制;
但在實際運用中,請求結果時候來源於伺服器,可能因為網路等問題延遲,出現單擊“開始”後許久沒轉動的問題。
這裡有必要進一步修正。 四、demo下載
代碼下載