iOS开发之转盘实现

最近在学习核心动画部分,今天学习了转盘的实现,在这里记录一下实现过程。

首先是用xib描述一个转盘view,分为三层,底部是一张底图背景色的图片,中间的是要旋转的ImageView,最上面是一个按钮,如图:

iOS开发之转盘实现_第1张图片

新建转盘view对象WheelView:在转盘view里要提供两个方法给外部使用,开始旋转和暂停旋转在构造方法中去加载xib。

#import <UIKit/UIKit.h>

@interface WheelView : UIView

+ (instancetype)wheelView;

- (void)start;

- (void)pause;

@end

+ (instancetype)wheelView {
    
    return [[[NSBundle mainBundle]loadNibNamed:NSStringFromClass(self) owner:nil options:nil]lastObject];
    
}


初始化完WheelView后去给转盘添加按钮,这些事情要在哪做?awakeFromNib方法还是initWithCoder?dan‘an(这个也是敏感词?)是awakeFromNib,因为在自定义view里面可能需要在类扩展中添加一些属性,跟xib中的view连线,但是initWithCoder调用的时候连线还没有完成好,而当调用awakeFromNib时,xib已经完全加载好了。

定义一个成员变量中间层的veiw,在这个view上来添加按钮,一个保存被选中的按钮,一个定时器

#import "WheelView.h"
#import "WheelButton.h"

@interface WheelView ()

/** centerview */
@property(nonatomic, weak) IBOutlet UIImageView *centerView;

//选中的按钮
@property(nonatomic, weak) UIButton *selectBtn;

/** 定时器 */
@property(nonatomic, strong) CADisplayLink *link;
@end

定时器进行懒加载:

- (CADisplayLink *)link {
    
    if (_link == nil) {
        
        _link = [CADisplayLink displayLinkWithTarget:self selector:@selector(angleChange)];
        
        //添加到主运行循环
        [_link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    }
    return _link;
}

定时器中执行的方法是改变中间层的view的transfrom属性,进行旋转:

- (void)angleChange {
    
    //规定1秒旋转45度
    
    //计算每一次调用旋转多少度:这个方法是一秒调用60次
    CGFloat angle = (45 / 60.0) * M_PI / 180.0;
    
    _centerView.transform = CGAffineTransformRotate(_centerView.transform, angle);
    
}

添加按钮的过程:

- (void)awakeFromNib {
    
    //允许UIImageView可以与用户交互
    _centerView.userInteractionEnabled = YES;
    
    CGFloat btnW = 68;
    CGFloat btnH = 143;
    CGFloat wh = self.bounds.size.width;
    
    //加载星座大图片
    UIImage *bigImage = [UIImage imageNamed:@"LuckyAstrology"];
    
    //加载星座选中时候的大图片
    UIImage *bigSelImage = [UIImage imageNamed:@"LuckyAstrologyPressed"];
    
    //这里要注意是像素,而不是点
    //获取像素与点的比例
    CGFloat scale = [UIScreen mainScreen].scale;
    CGFloat imageW = bigImage.size.width / 12 * scale;
    CGFloat imageH = bigImage.size.height * scale;
    
    //添加按钮
    for (int i = 0; i < 12; i++) {
        WheelButton *btn = [WheelButton buttonWithType:UIButtonTypeCustom];
        
        //设置按钮的位置
        btn.layer.anchorPoint = CGPointMake(0.5, 1);
        
        btn.layer.bounds = CGRectMake(0, 0, btnW, btnH);
        
        btn.layer.position = CGPointMake(wh * 0.5, wh * 0.5);
        
        //旋转角度
        CGFloat angle = (30 * i) / 180.0 * M_PI;
        btn.transform = CGAffineTransformMakeRotation(angle);
        
        [_centerView addSubview:btn];
        
        //设置按钮的图片
        //计算裁剪区域
        CGRect clipR = CGRectMake(i * imageW, 0, imageW, imageH);
        
        //裁剪图片
        CGImageRef imgR = CGImageCreateWithImageInRect(bigImage.CGImage, clipR);
        
        UIImage *image = [UIImage imageWithCGImage:imgR];
        
        //设置按钮图片
        [btn setImage:image forState:UIControlStateNormal];
        
        //设置选中时候的图片
        imgR = CGImageCreateWithImageInRect(bigSelImage.CGImage, clipR);
        image = [UIImage imageWithCGImage:imgR];
        
        //设置选中时的背景图片
        [btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
        
        //设置按钮尺寸
        [btn setImage:image forState:UIControlStateSelected];
        
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        
        //默认选中第一个
        if (i == 0) {
            [self btnClick:btn];
        }
        
    }
    
}

- (void)btnClick:(UIButton *)btn {
    
    _selectBtn.selected = NO;
    btn.selected = YES;
    _selectBtn = btn;
    
}

由于UIButton是不能设置它里面的image的尺寸的,所以这里需要自定义一个UIButton:WheelButton,继承自UIButton,它里面主要重写一些系统UIButton不能做到的事情

#import "WheelButton.h"

@implementation WheelButton


/**
*  设置UIImageView的尺寸,contentRect是按钮的尺寸
*/
- (CGRect)imageRectForContentRect:(CGRect)contentRect {
    
    //计算UIImageView控件的尺寸
    CGFloat imageW = 40;
    CGFloat imageH = 46;
    CGFloat imageX = (contentRect.size.width - imageW) * 0.5;
    CGFloat imageY = 20;
    return CGRectMake(imageX, imageY, imageW, imageH);
}

//重写该方法目的:取消图片高亮状态
- (void)setHighlighted:(BOOL)highlighted {
    
}

// 寻找最合适的view,让Button只能点击上半部分
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGFloat btnW = self.bounds.size.width;
    CGFloat btnH = self.bounds.size.height;
    
    CGFloat x = 0;
    CGFloat y = btnH / 2;
    CGFloat w = btnW;
    CGFloat h = y;
    CGRect rect = CGRectMake(x, y, w, h);
    if (CGRectContainsPoint(rect, point)) {
        return nil;
    }else{
        return [super hitTest:point withEvent:event];
    }
    
}

@end

最后封装转盘view的开始旋转和暂停旋转的方法

- (void)start {
    
    self.link.paused = NO;
    
}

- (void)pause {
    
    self.link.paused = YES;

}

控制器中在主窗口添加一个wheelview

#import "ViewController.h"
#import "WheelView.h"

@interface ViewController ()

/** 转盘view */
@property(nonatomic, weak) WheelView *wheelView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //添加转盘
    WheelView *wheelView = [WheelView wheelView];
    
    wheelView.center = self.view.center;
    
    [self.view addSubview:wheelView];
    
    _wheelView = wheelView;
    
}

#pragma mark - 开始旋转
- (IBAction)start:(id)sender {
    
    [_wheelView start];
    
}

#pragma mark - 暂停旋转
- (IBAction)pause:(id)sender {
    
    [_wheelView pause];
    
}

@end

这样就实现完了。效果图:

iOS开发之转盘实现_第2张图片

你可能感兴趣的:(iOS开发之转盘实现)