1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 《幸运大转盘》代码分享

《幸运大转盘》代码分享

时间:2020-11-28 05:24:40

相关推荐

《幸运大转盘》代码分享

《幸运大转盘》有一句代码是这样的:

self.rotateView.transform=CGAffineTransformMakeRotation(-angle);

它出现在延迟派遣消息dispatch_after里面,然而你真的看懂它了吗?

本文将揭秘这句代码的真相!红字黄底标出!

#import"ViewController.h"

#import"ZHYView.h"

@interfaceViewController()

@end

@implementationViewController

- (void)viewDidLoad {

[superviewDidLoad];

//让控制器的view以拉伸的方式设置成图片

self.view.layer.contents= (__bridgeid)([UIImageimageNamed:@"LuckyBackground"].CGImage);

//创建转盘的对象

ZHYView*rotateView= [ZHYViewrotateImage];

//设置转盘在屏幕上居中显示

rotateView.center=self.view.center;

//把装盘添加到控制器当中

[self.viewaddSubview:rotateView];

//程序一运行就让锯齿图片旋转

[rotateViewstartRotate];

}

//设置状态栏样式为白色字体,更好看一些

-(UIStatusBarStyle)preferredStatusBarStyle{

returnUIStatusBarStyleLightContent;

}

@end

#import <UIKit/UIKit.h>

@interface CZView : UIView

+ (instancetype)rotateView;

- (void)startRotate;

@end

#import "ZHYView.h"

#define kButtonCount 12

@interface ZHYView () <UIAlertViewDelegate>

@property (weak, nonatomic) IBOutlet UIImageView *rotateView;

@property (nonatomic,weak) UIButton *lastButton;

@property (nonatomic,strong) CADisplayLink *link;

@end

@implementation ZHYView

// 开始旋转

-(void)startRotate{

// CADisplayLink刷帧,默认每秒刷新60次,该定时器创建之后,默认是不会执行的,需要把它加载到主消息循环中才会被执行

CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];

// 将CADisplayLink定时器加载到主循环中

[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

// 给属性link赋值,便于后面对CADisplayLink定时器对象link进行设置

self.link = link;

}

// 旋转

-(void)rotate{

CGFloat round = 5;

CGFloat angle = 2 * M_PI / 60 / round;

// 设置CADisplayLink定时器对象link,让rotateView每5秒转一圈

self.rotateView.transform = CGAffineTransformRotate(self.rotateView.transform, angle);

}

// 开始选号的点击事件

- (IBAction)pickNumber:(UIButton *)sender {

// 如果没有选中任何一个button的时候不旋转

if (!self.lastButton) {

return;

}

// 让CADisplayLink定时器对象link暂停下来,避免UIAlertView的代理方法(点击弹出提示框的确定按钮后执行的方法)结束后选中的button跳屏

self.link.paused = YES;

// 关掉大转盘的用户交互

self.userInteractionEnabled = NO;

// 创建一个基本动画,让转盘快速旋转以备选号

CABasicAnimation *ani = [[CABasicAnimation alloc] init];

// 设置关键路径

ani.keyPath = @"transform.rotation";

// 记录每个button对应的初始角度

CGFloat angle = self.lastButton.tag * 2 * M_PI / 12;

// 设置属性toValue为了让选中的button快速旋转后指向转盘的正上方

ani.toValue = @(2 * M_PI * 5 - angle);

// 设置快速旋转动画的持续时间

ani.duration = 2;

// 修改动画的默认模式,不让动画在结束后复位

ani.fillMode = kCAFillModeForwards;

// 该BOOL属性不设置的话,动画默认修改不成功;

ani.removedOnCompletion = NO;

// 将动画添加到layer上

[self.rotateView.layer addAnimation:ani forKey:@"key"];

// 延迟 ani.duration 时间后派遣{}中的消息

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(ani.duration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

/*

这里需要详细解释一下:

假设:

原始角度:狮子座在最上面: 0

当你点击大转盘的星座按钮时狮子座的角度:A

当你接着点击选号按钮时狮子座的角度:B

动画结束后狮子座的位置被设定了在最上面:0

如果下面这句代码不设置,就会发生跳屏现象,即选中的按钮会跳到角度 B

*/

self.rotateView.transform = CGAffineTransformMakeRotation(-angle);

// 创建提示视图,显示信息

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"幸运大转盘,赚的就是你" message:@"13579" delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];

// 显示提示视图

[alert show];

// 开启大转盘的用户交互

self.userInteractionEnabled = YES;

});

}

// UIAlertView的代理方法,在点击cancelButtonTitle:@"确定"的时候会执行

-(void)alertView:(UIAlertView *)alertViewclickedButtonAtIndex:(NSInteger)buttonIndex{

// 移除指定AnimationForKey:@"key"的动画

[self.rotateView.layer removeAnimationForKey:@"key"];

/*

其实在大转盘选号结束后这么设置可以让大转盘恢复初始状态[随便玩玩]

self.lastButton.selected = NO;

self.lastButton = nil;

*/

// 让CADisplayLink定时器对象link重新计时

self.link.paused = NO;

}

// button的点击事件

-(void)clickButton:(UIButton *)button{

// 取消上一个button的选中状态

self.lastButton.selected = NO;

// 设置点击到的button的选中状态

button.selected = YES;

// 点击事件的最后将当前button赋值给lastbutton

self.lastButton = button;

}

// 布局子控件

-(void)layoutSubviews{

// 遍历锯齿图片里面的子控件(button)设置frame

for (int i = 0; i < self.rotateView.subviews.count; i++) {

UIButton *button = self.rotateView.subviews[i];

CGFloat buttonCenterX = self.bounds.size.width * 0.5;

CGFloat buttonCenterY = self.bounds.size.height * 0.5;

button.frame = CGRectMake(0, 0, 68, 143);

button.center = CGPointMake(buttonCenterX,buttonCenterY);

// 设置每个button的初始角度

CGFloat angle = i * 2 * M_PI / 12;

// 将每个button散开

button.transform = CGAffineTransformMakeRotation(angle);

// 设置button的内边距

[button setContentEdgeInsets:UIEdgeInsetsMake(-44, 0, 0, 0)];

}

}

//裁剪图片

-(UIImage *)clipImage:(UIImage *)image withIndex:(int)index{

//设置将要从image获取的裁剪到的图片的frame,注意宽高需要乘以设备的缩放因子

CGFloat w = image.size.width / 12 * [UIScreen mainScreen].scale;

CGFloat h = image.size.height * [UIScreen mainScreen].scale;

CGFloat x = index * w;

CGFloat y = 0;

// 获取裁剪image中rect部分裁剪的图片

CGImageRef imageRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(x, y, w, h));

// 通过CGImageRef的image转成UIimage,scale是缩放因子,需要手动调试出一个合适的值,orientation是一个方向枚举,0表示默认方向

return [UIImage imageWithCGImage:imageRef scale:2 orientation:0];

}

//从nib加载

-(void)awakeFromNib{

// 创建12个button

for (int i = 0; i < kButtonCount; i++) {

// 创建button

UIButton * button = [[UIButton alloc] init];

// 修改button的锚点为中间最下

button.layer.anchorPoint = CGPointMake(0.5, 1);

// 绑定button的tag属性,便于确定每个button的初始位置角度

button.tag = i;

// 加载button默认和选中两个状态的原图

UIImage *image = [UIImage imageNamed:@"LuckyAstrology"];

UIImage *imagePress = [UIImage imageNamed:@"LuckyAstrologyPressed"];

// 获取通过自定义的方法将两个原图按顺序裁剪的图片

image = [self clipImage:image withIndex:i];

imagePress = [self clipImage:imagePress withIndex:i];

// 给button的默认和选中状态设置裁剪好的图片

[button setImage:image forState:UIControlStateNormal];

[button setImage:imagePress forState:UIControlStateSelected];

// 设置button的背景图片

[button setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];

// 设置button的点击事件clickButton:

[button addTarget:self action:@selector(clickButton:) forControlEvents:UIControlEventTouchUpInside];

// 将button添加到rotateView中

[self.rotateView addSubview:button];

}

}

// 一个返回值为大转盘对象的类方法,便于外部访问

+(instancetype)rotateImage{

return [[NSBundle mainBundle] loadNibNamed:@"ZHYView" owner:nil options:nil][0];

}

@end

运行结果赏析:

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。