幸运转盘(CALayer实现)

一.简单方式的代码实现

//
//  ViewController.m
//  幸运转盘
//
//  Created by 许磊 on 2019/3/14.
//  Copyright © 2019年 xulei. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

/**存放切割好的图片*/
@property (nonatomic,strong) NSMutableArray *imageArray;

/**箭头*/
@property (nonatomic,strong) CALayer *layer;

/**link*/
@property (nonatomic,strong) CADisplayLink *link;

@end

@implementation ViewController

- (void)viewDidLoad {
    
    [super viewDidLoad];
    
    //设置背景图片
    self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"LuckyBackground"]];
    
    //转盘
    CALayer *turnttableLayer = [CALayer layer];
    turnttableLayer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"LuckyRotateWheel"].CGImage);
    turnttableLayer.position = CGPointMake(self.view.frame.size.width/2, self.view.frame.size.height/2);
    turnttableLayer.bounds = CGRectMake(0, 0, 256, 256);
    [self.view.layer addSublayer:turnttableLayer];
    
    //切割图片
    self.imageArray = [NSMutableArray array];
    for (int i = 0; i < 12; i++) {
        UIImage *img = [UIImage imageNamed:@"LuckyAstrology"];
        CGImageRef imgRef = img.CGImage;
        CGImageRef finallRef = CGImageCreateWithImageInRect(imgRef, CGRectMake(0+(img.size.width/12)*i, 0, img.size.width/12, img.size.height));
        UIImage *temp = [UIImage imageWithCGImage:finallRef];
        [self.imageArray addObject:temp];
    }
    
    //添加箭头
    self.layer = [CALayer layer];
    _layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"LuckyRototeSelected"].CGImage);
    _layer.bounds = CGRectMake(0, 0, 48, 81);
    _layer.position = CGPointMake(128, 128);
    _layer.anchorPoint = CGPointMake(0.5, 1.5);
    [turnttableLayer addSublayer:_layer];
    
    //添加图片
    for (int i = 0; i < 12; i++) {
        CALayer *layer = [CALayer layer];
        UIImage *temp = [self.imageArray objectAtIndex:i];
        layer.contents = (__bridge id _Nullable)(temp.CGImage);
        //layer.backgroundColor = [UIColor blackColor].CGColor;
        layer.bounds = CGRectMake(0, 0, 35, 45);
        layer.position = CGPointMake(128, 128);
        layer.anchorPoint = CGPointMake(0.5, 2.4);
        layer.transform = CATransform3DMakeRotation((M_PI*2/12)*i, 0, 0, 1);
        [turnttableLayer addSublayer:layer];
    }
    
    //添加按钮
    UIButton *begBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [begBtn setImage:[UIImage imageNamed:@"LuckyCenterButtonPressed"] forState:UIControlStateNormal];
    begBtn.frame = CGRectMake(self.view.frame.size.width/2-40, self.view.frame.size.height/2-40, 80, 80);
    [begBtn addTarget:self action:@selector(gameStart) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:begBtn];
    
    self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];
    _link.preferredFramesPerSecond = 20;//设置每秒刷新次数
    [self.link addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    self.link.paused = !(self.link.paused);
}



-(void)gameStart{
    //暂停
    self.link.paused = !(self.link.paused);
}

-(void)rotate{
    //动画一般放在
    _layer.transform = CATransform3DRotate(_layer.transform, (2*M_PI)/12, 0, 0, 1);
}

@end
运行结果

项目链接
链接:https://pan.baidu.com/s/1sKxwEwWypTg8iCm2-v1SLQ 密码:fiyz

二.抽出类的方式实现

1.设置背景图片

//设置背景图片
self.view.layer.contents = (__bridge id _Nullable)([UIImage 
                                         imageNamed:@"LuckyBackground"].CGImage);

2.定义一个类用来管理转盘视图:LuckyWheel

  1. 用户怎么用
    创建转盘视图 frame
    返回结果

a.创建一个Xib文件 负责管理界面的搭建

创建Xib

更改尺寸
添加视图
添加约束
关联

b.快速创键当前类的方法

#import 

@interface LuckyWheelView : UIView

/**快速创建当前这个类的对象-自己最了解自己是什么*/
+(LuckyWheelView *)wheel;

@end

@implementation LuckyWheelView

+(LuckyWheelView *)wheel{
    
    //创建当前这个类的对象
    LuckyWheelView *wheelView = [[[NSBundle mainBundle] loadNibNamed:@"LuckyWheel" owner:nil options:nil] lastObject];
    //设置属性
    
    //返回对象
    return wheelView;
}

@end

c.添加PCH文件

添加

修改设置

d.viewDidLoad里面添加创建的视图

//创建转盘视图
LuckyWheelView *luckyView = [LuckyWheelView wheel];
//中心
luckyView.center = self.view.center;
//显示
[self.view addSubview:luckyView];

e.代码关联控件

关联

f.写一个类别,裁剪图片

#import 

@interface UIImage (ClipImage)

/**裁剪图片*/
+(UIImage *)clipImageNamed:(NSString *)imageName index:(int)index;

/**裁剪图片*/
+(UIImage *)clipImage:(UIImage *)img Rect:(CGRect)frame;

@end


#import "UIImage+ClipImage.h"

@implementation UIImage (ClipImage)

+(UIImage *)clipImageNamed:(NSString *)imageName index:(int)index{
    //读取图片
    UIImage *img = [UIImage imageNamed:imageName];
    
    //自己画的图片不能自己去匹配scale 乘上屏幕的缩放比例
    //8plus,[UIScreen mainScreen].scale是3x,没有3x就会发生错误
    
    //计算每一个的宽度和高度
    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 clipImage:img Rect:frame];
}

+(UIImage *)clipImage:(UIImage *)img Rect:(CGRect)frame{
    
    //裁剪图片
    CGImageRef imgRef = CGImageCreateWithImageInRect(img.CGImage, frame);
    
    UIImage *newImage = [UIImage imageWithCGImage:imgRef scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp];
    

    return newImage;
}

@end

g.创建按钮,对按钮旋转,截取图片到按钮上

//当Xib文件的内容加载完毕,系统就会自动调用这个方法
//你需要做什么就可以在这里面做
//使用xib方法创建视图,不会调动init和initWithFrame方法
-(void)awakeFromNib{
    [super awakeFromNib];
    
    //设置视图背景颜色
    self.backgroundColor = [UIColor clearColor];
    
    //给转盘添加按钮 不接受事件
    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];
        //旋转
        btn.transform = CGAffineTransformRotate(btn.transform, ((M_PI*2)/12)*i);
    
        //截取图片 1.image 2.index
        UIImage *newImage = [UIImage clipImageNamed:@"LuckyAstrology" index:i];
        
        //将图片显示到按钮上
        [btn setImage:newImage forState:UIControlStateNormal];
        
        [self.wheelImagView addSubview:btn];
        
        btn.tag = i+1;
        NSLog(@"%@",NSStringFromCGRect(btn.frame));
        
    }
    
}

h.选号按钮触发的事件

//选号按钮做的事情
- (IBAction)selectNumButonDidClicked:(UIButton *)sender {
    if (self.link != nil) {
        //暂停 或者 开始
        //self.link.paused = !(self.link.paused);
        if (self.link.paused == YES) {
            _link.paused = NO;
            self.selectedButton.selected = NO;
        } else{
            //1.先暂停
            _link.paused = YES;
            //2.继续旋转一个角度
            [self stopChangePostion];
        }
        //删除定时器
        //[self.link invalidate];
    } else{
        //创建定时器 执行任务
        self.link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];
        //_link.preferredFramesPerSecond = 1;
        //启动定时器
        [_link addToRunLoop:[NSRunLoop currentRunLoop]  forMode:NSRunLoopCommonModes];
    }
}

//旋转
-(void)rotate{
    self.wheelImagView.transform = CGAffineTransformRotate(self.wheelImagView.transform, M_PI/30.0);
}

-(void)stopChangePostion{
    //使用2秒钟旋转一个角度
    [UIView animateWithDuration:2 animations:^{
        self.wheelImagView.transform = CGAffineTransformRotate(self.wheelImagView.transform, M_PI*8/9.0);
    }completion:^(BOOL finished) {
        for (UIButton *btn in _wheelImagView.subviews) {
            //控件通过transform动画移动,自身位置不变
            //由ModelLayer确认走到那个位置
            //由PresentLayer确认显示
            //自己没有发生改变
            NSLog(@"%lu",btn.tag);
            NSLog(@"%@",NSStringFromCGRect(btn.frame));
        }
        
        //确认箭头指向那个按钮
        
        //1.获取旋转之后弧度
        CGFloat hudu = [Factory getRadianDegreeFromTransform:self.wheelImagView.transform];
        //2.根据弧度计算转了几个按钮的弧度
        int index = (hudu-M_PI/12)/(M_PI/6.0);
        if (hudu - index*M_PI/6.0 > 0) {
            index++;
        }
        
        NSLog(@"%d",index);
        
        //通过tag值获取按钮对象
        UIButton *btn = [self.wheelImagView viewWithTag:12-index+1];
        btn.selected = YES;
        
        self.selectedButton = btn;
        
    }];
}
运行结果

项目链接
链接:https://pan.baidu.com/s/1p3z_KE8hCSFkRuj1E4p4mg 密码:6c1q

遇到的问题

  • 添加到工程的文件一定要勾上targets,不然是不能使用的

    添加示意图

  • 文件名写错了,Rename的方法

    Rename

  • 裁剪图片,系统无法分辨大小,不能很好的显示。我们需要获当前屏幕的scale然后进行修改。有时候导入到工程里面的图片有时候在一些模拟器里面可以正常布局,在一些不可以,是因为缺少2X或者3X图片。2X或者3X图片是为了应对不同屏幕而产生的,如果缺少,可以复制1X,对其改名改大小便可

你可能感兴趣的:(幸运转盘(CALayer实现))