Demo6—抽奖转盘
一.搭建界面
1.设置背景图片
self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"LuckyBackground"].CGImage);
2.自定义一个类管理转盘视图,并用xib关联界面
- 创建一个xib文件,负责管理界面的基本搭建,与LuckWheelView类关联
并设置图片的大小
- 写一个类方法快速创建当前类LuckWheelView的一个对象
+ (LuckWheelView *)wheel{
//创建当前类的一个对象
LuckWheelView *luckView = [[[NSBundle mainBundle] loadNibNamed:@"LuckWheelView" owner:self options:nil] lastObject];
//放回对象
return luckView;
}
- 在控制类中用户使用,创建转盘视图,并设置视图处于主视图中心
LuckWheelView *luckView = [LuckWheelView wheel];
luckView.center = self.view.center;
- 让这个转盘视图显示到主视图上
[self.view addSubview:luckView];
3.当xib文件加载结束后执行后续事件
- 由于xib中搭建的界面背景是白色的,所以,为了视觉感,将其背景颜色设为透明
self.backgroundColor = [UIColor clearColor];
- 给转盘上添加12个按钮,不接收事件,设置按钮的中心位置为视图的中心;设置按钮的大小;设置按钮的锚点在矩形的下边线中间,以便其他按钮通过旋转形成圆盘;给按钮设置背景图片,并把各个按钮添加到转盘视图上,不可添加到主视图上,因为给主视图上添加视图是添加到主视图的最外层,会覆盖一部分视图;旋转按钮,每次循环旋转30°;给按钮上添加内容图片,表示抽奖结果。
for (int i = 0; i < 12; i++) {
UIButton *btn = [[UIButton alloc] init];
//设置位置
btn.layer.position = self.center;
//设置尺寸
btn.layer.bounds = CGRectMake(0, 0, 68, 143);
//设置锚点
btn.layer.anchorPoint = CGPointMake(0.5, 1);
//设置图片
[btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
[self.wheelImageView addSubview:btn];
//旋转图片
btn.transform = CGAffineTransformRotate(btn.transform, M_PI * 2 / 12 * i);
}
- 为了提高可移植性,把截取图片写成一个工具类别,分两步实现,第一步是已知所裁图片的名称和裁第几个,然后根据得到的图片和范围裁剪需要的那个图片。
- 第一步:先通过已知的图片名称读取图片,然后计算截取一个图片的宽高,但是为了适应不同型号的手机大小,在这里需要乘一个倍数,最后计算出裁剪的范围
+ (UIImage *)clipWithImageNamed:(NSString *)imgName index:(int)index{
//读取图片
UIImage *img = [UIImage imageNamed:imgName];
//计算每一个的宽高
CGFloat width = img.size.width / 12.0 * [UIScreen mainScreen].scale;
CGFloat height = img.size.height * [UIScreen mainScreen].scale;
//计算裁剪的范围
CGRect frame = CGRectMake(index * width, 0, width, height);
return [self clipWithImage:img rect:frame];
}
- 第二步:算出要裁剪的范围后,调用CGImageCreateWithImageInRect方法直接裁取指定范围内的图片
CGImageRef是一个结构体指针,这个结构用来创建像素位图,可以通过操作存储的像素位来编辑图片
typedef struct CF_BRIDGED_TYPE(id) CGImage *CGImageRef;
+(UIImage *)clipWithImage:(UIImage *)img rect:(CGRect)frame{
CGImageRef imgRef = CGImageCreateWithImageInRect(img.CGImage, frame);
/*
匹配屏幕大小
参数1: cgImage:image.CGImage image为原始图片
参数2:scale:原始图片放大倍数
参数3:orientation:控制image的绘制方向
*/
UIImage *newImage = [UIImage imageWithCGImage:imgRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
return newImage;
}
- 在for循环那里加上裁取内容图片这一步
//截取图片
UIImage *orgLongImage = [UIImage clipWithImageNamed:@"LuckyAstrology" index:i];
//将图片显示到按钮上
[btn setImage:orgLongImage forState:UIControlStateNormal];
二.触发事件
1.在LuckWheelView类中关联xib中开始抽奖按钮的时间
2.设置一个定时器控制转盘的开始和暂停
- 定一个属性变量link
@property(nonatomic, strong) CADisplayLink *link;
- 当link为空时转盘开始,不为空时转盘暂停,转盘暂停之后继续转一个角度经过一个缓冲后再停下
- (IBAction)startButtonDidClicked:(id)sender {
if (self.link) {
//self.link.paused = !_link.paused;
if (self.link.paused == YES) {
//1.暂停
_link.paused = NO;
} else {
_link.paused = YES;
//2.继续旋转一个角度
[self stop];
}
} else{
//创建定时器 执行旋转任务
self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];
//启动定时器
[_link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
}
- 转盘开始转的方法
- (void)rotate{
_wheelImageView.transform = CGAffineTransformRotate(_wheelImageView.transform, M_PI/30);
}
3.转盘暂停后再转一个角度缓冲并点亮箭头所指的那个按钮,首先需要计算出箭头所指方向…
- (void)stop{
[UIView animateWithDuration:2 animations:^{
self.wheelImageView.transform = CGAffineTransformRotate(self.wheelImageView.transform, M_PI*8/9.0);
} completion:^(BOOL finished) {
//确定剪头指向哪个按钮
//1.获取旋转之后的弧度
CGFloat hudu = [self getRadianDegreeFromTransform:self.wheelImageView.transform];
//2.根据弧度计算旋转了几个按钮
int index = (hudu - M_PI/12.0)/(M_PI/6.0);
if (hudu - index*M_PI/6.0 > 0) {
index++;
}
//3.通过tag值获取按钮对象
_selectedButton = [self.wheelImageView viewWithTag:12-index+1];
_selectedButton.selected = YES;
}];
}
- 计算旋转的弧度
- (CGFloat)getRadianDegreeFromTransform:(CGAffineTransform)transform{
CGFloat rotate = acosf(transform.a);
// 旋转180度后,需要处理弧度的变化
if (transform.b < 0) {
rotate = M_PI*2 - rotate;
}
return rotate;
}