美文网首页
16-核心动画

16-核心动画

作者: 木喳喳的夏天 | 来源:发表于2016-03-31 16:03 被阅读22次

画板(图片处理)

  • 为了能对照片提供更多的手势操作,需要把从相册中选取的照片放置到UIImageView中,然后对控件添加手势操作即可完成对照片的对应操作
  • 创建一个专门用来处理图片的View(ImageHandleView)

隐式动画

  • 只有非根层view的layer才有隐式动画,根层view的layer没有隐式动画

时钟动画

  • 首先定义宏,每秒钟秒针、每分钟分针、每小时时针和每分钟时针旋转的度数
// 一秒钟秒针转6°
#define perSecondA 6

// 一分钟分针转6°
#define perMinuteA 6

// 一小时时针转30°
#define perHourA 30

// 每分钟时针转多少度
#define perMinuteHourA 0.5
  • 时钟界面的搭建
@interface ViewController ()

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

@property (nonatomic, weak) CALayer *secondLayer;

@property (nonatomic, weak) CALayer *minuteLayer;

@property (nonatomic, weak) CALayer *hourLayer;

@end
  • 在viewDidLoad中对界面进行初始化
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 添加时针,因为先添加的在下面
    [self setUpHourLayer];
    
    // 添加分针
    [self setUpMinuteLayer];
    
    // 添加秒针
    [self setUpSecondLayer];
    
    // 添加定时器
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
    
    [self timeChange];
    
}
  • 以此初始化各个指针
#pragma mark - 添加秒针
- (void)setUpSecondLayer
{
   CALayer *secondL = [CALayer layer];
    
    secondL.backgroundColor = [UIColor redColor].CGColor;
    
    // 设置锚点
    secondL.anchorPoint = CGPointMake(0.5, 1);
    
    secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
    
    [_clockView.layer addSublayer:secondL];
    
    _secondLayer = secondL;
}

#pragma mark - 添加分针
- (void)setUpMinuteLayer
{
    CALayer *layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor;
    
    // 设置锚点
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _minuteLayer = layer;
}

#pragma mark - 添加时针
- (void)setUpHourLayer
{
    CALayer *layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor;
    
    // 设置锚点
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _hourLayer = layer;
}
  • 定时器调用的方法
- (void)timeChange
{
    // 获取当前的系统的时间
    
    // 获取当前日历对象
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
    // 获取日期的组件:年月日小时分秒
    // components:需要获取的日期组件
    // fromDate:获取哪个日期的组件
    // 经验:以后枚举中有移位运算符,通常一般可以使用并运算(|)
    NSDateComponents  *cmp = [calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
    
    // 获取秒
    NSInteger second = cmp.second;
    
    // 获取分
    NSInteger minute = cmp.minute;
    
    // 获取小时
    NSInteger hour = cmp.hour;
    
    // 计算秒针转多少度
    CGFloat secondA = second * perSecondA;
    
    // 计算分针转多少度
    CGFloat minuteA = minute * perMinuteA;
    
    // 计算时针转多少度
    CGFloat hourA = hour * perHourA + minute * perMinuteHourA;
    
    // 旋转秒针
    _secondLayer.transform = CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);
    
    // 旋转分针
    _minuteLayer.transform = CATransform3DMakeRotation(angle2radion(minuteA), 0, 0, 1);
    
    // 旋转小时
    _hourLayer.transform = CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}

核心动画(CABasicAnimation)

  • 创建动画-->描述修改哪个属性产生动画-->设置值-->设置动画执行的次数-->取消动画反弹-->将动画添加到layer上
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 创建动画
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    // 描述下修改哪个属性产生动画
    // anim.keyPath = @"position";
    // 只能是layer属性
    anim.keyPath = @"transform.scale";
    
    // 设置值
    // anim.toValue = [NSValue valueWithCGPoint:CGPointMake(250, 500)];
    
    anim.toValue = @0.5;
    
    // 设置动画执行次数
    anim.repeatCount = MAXFLOAT;
    
    // 取消动画反弹
    // 设置动画完成的时候不要移除动画
    anim.removedOnCompletion = NO;
    
    // 设置动画执行完成要保持最新的效果
    anim.fillMode = kCAFillModeForwards;
    
    [_imageV.layer addAnimation:anim forKey:nil];
    
}

核心动画(CAKeyFrameAnimation)

  • 开始触摸时,创建UIBezierPath并设置起点
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // touch
    UITouch *touch = [touches anyObject];
    
    // 获取手指的触摸点
    CGPoint curP = [touch locationInView:self];
    
    // 创建路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    _path = path;
    
    // 设置起点
    [path moveToPoint:curP];
    
}
  • 触摸移动时,获取触摸点并添加路径
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // touch
    UITouch *touch = [touches anyObject];
    
    // 获取手指的触摸点
    CGPoint curP = [touch locationInView:self];
    
    [_path addLineToPoint:curP];
    
    [self setNeedsDisplay];
}
  • 结束触摸时,给imageView添加核心动画
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 给imageView添加核心动画
    // 添加核心动画
    
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    
    anim.keyPath = @"position";
    
    // anim.values = @[@(angle2Radion(-10)),@(angle2Radion(10)),@(angle2Radion(-10))];
    
    anim.path = _path.CGPath;
    
    anim.duration = 1;
    
    anim.repeatCount = MAXFLOAT;
    
    [[[self.subviews firstObject] layer] addAnimation:anim forKey:nil];
}

核心动画(CATransition)

  • CATransition即转场动画
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    // 转场代码
    if (i == 4) {
        i = 1;
    }
    // 加载图片名称
    NSString *imageN = [NSString stringWithFormat:@"%d",i];
    
    _imageView.image = [UIImage imageNamed:imageN];
    
    i++;
    
    // 转场动画
    CATransition *anim = [CATransition animation];
    
    anim.type = @"pageCurl";
    
    anim.duration = 2;
    
    [_imageView.layer addAnimation:anim forKey:nil];
    
}

核心动画(CAAnimationGroup)

  • CAAnimationGroup即动画组
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 同时缩放,平移,旋转
    CAAnimationGroup *group = [CAAnimationGroup animation];
    
    CABasicAnimation *scale = [CABasicAnimation animation];
    scale.keyPath = @"transform.scale";
    scale.toValue = @0.5;
    
    CABasicAnimation *rotation = [CABasicAnimation animation];
    rotation.keyPath = @"transform.rotation";
    rotation.toValue = @(arc4random_uniform(M_PI));
    
    CABasicAnimation *position = [CABasicAnimation animation];
    position.keyPath = @"position";
    position.toValue = [NSValue valueWithCGPoint:CGPointMake(arc4random_uniform(200), arc4random_uniform(200))];
    
    group.animations = @[scale,rotation,position];
    
    [_redView.layer addAnimation:group forKey:nil];
    
}

UIView和核心动画(Core Animation)的区别

  • 通过分别使用UIView动画和核心动画观察,核心动画并不会真实的改变图层的属性值

  • 而UIView动画必须通过修改属性的真实值,才会有动画效果

  • 如果以后做动画的时候,不需要与用户交互,通常使用核心动画(比如转场效果)

  • 注意:核心动画中,取消反弹的代码必须放在图层添加动画之前

      anim.removedOnCompletion = NO;
      anim.fillMode = kCAFillModeForwards;
      [self.redView.layer addAnimation:anim forKey:nil];
    
  • 核心动画要想监听动画的完成,需要实现代理,但是不需要遵守任何协议

// 动画完成的时候调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"%@", NSStringFromCGPoint(_redView.layer.position));
}
  • UIView动画在完成的时候,可以使用block定义动画完成后要执行的代码
    [UIView animateWithDuration:0.25 animations:^{
        
        _redView.layer.position = CGPointMake(150, 400);

    } completion:^(BOOL finished) {

            NSLog(@"%@", NSStringFromCGPoint(_redView.layer.position));

        }];

转盘的设计

  • 首先是界面的搭建,直接从xib中加载即可,创建一个类方法返回xib所对应的View
+ (instancetype)wheelView
{
   return  [[NSBundle mainBundle] loadNibNamed:@"WheelView" owner:nil options:nil][0];
}
  • 注意:initWithCoder:方法只是在加载xib的时候会调用,但是并不会将xib中的控件和代码进行连线
  • 所以需要在awakeFromNib方法中,进行添加和设置按钮的操作等
- (void)awakeFromNib
{
    // UIImageView是个比较特殊的View,默认不会与用户进行交互,需要设置userInteractionEnabled为YES
    _centerView.userInteractionEnabled = YES;
    CGFloat btnW = 68;
    CGFloat btnH = 143;
    
     CGFloat wh = self.bounds.size.width;
    
    // 加载大图片
    UIImage *bigImage = [UIImage imageNamed:@"LuckyAstrology"];
    
    // 加载大图片
    UIImage *selBigImage = [UIImage imageNamed:@"LuckyAstrologyPressed"];
    
    // 获取当前使用的图片像素和点的比例
    CGFloat scale = [UIScreen mainScreen].scale;
    CGFloat imageW = bigImage.size.width / 12 * scale;
    CGFloat imageH = bigImage.size.height * scale;
    // CGImageRef image:需要裁减的图片
    // rect:裁减区域
    // 裁减区域是以像素为基准
    // CGImageCreateWithImageInRect(CGImageRef image, CGRect rect)
    
    // 添加按钮
    for (int i = 0; i < 12; i++) {
        WheelButton *btn = [WheelButton buttonWithType:UIButtonTypeCustom];
        
        // 设置按钮的位置
        btn.layer.anchorPoint = CGPointMake(0.5, 1);
        
        btn.bounds = CGRectMake(0, 0, btnW, btnH);
        
        btn.layer.position = CGPointMake(wh * 0.5, wh * 0.5);
        
        // 按钮的旋转角度
        CGFloat radion = (30 * i) / 180.0 * M_PI;
        
        btn.transform = CGAffineTransformMakeRotation(radion);
        
        [_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(selBigImage.CGImage, clipR);

        image = [UIImage imageWithCGImage:imgR];
        
        // 设置按钮的图片
        [btn setImage:image forState:UIControlStateSelected];
        
        // 设置选中背景图片
        [btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
        
        // 监听按钮的点击
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        
        // 默认选中第一个
        if (i == 0) {
            [self btnClick:btn];
        }
        
    }
}

- (void)btnClick:(UIButton *)btn
{
    _selBtn.selected = NO;
    btn.selected = YES;
    _selBtn = btn;
}
  • 开始旋转的时候,使用CABasicAnimation创建动画,并添加到self.centerView的layer上
#pragma mark - 开始旋转
- (void)start
{
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    anim.keyPath = @"transform.rotation";
    
    anim.toValue = @(M_PI * 2);
    
    anim.duration = 2;
    
    anim.repeatCount = MAXFLOAT;
    
    [_centerView.layer addAnimation:anim forKey:nil];
}
  • 当需要修改系统控件的属性的时候,需要自定义控件并集成系统的控件,重写其中的方法即可
// 设置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
{
    
}

相关文章

  • 16-核心动画

    画板(图片处理) 为了能对照片提供更多的手势操作,需要把从相册中选取的照片放置到UIImageView中,然后对控...

  • IOS 核心动画CoreAniamation总结

    iOS 核心动画是基于CALayer层的动画,UIView动画是系统对核心动画的封装,核心动画相对UIView来说...

  • iOS基础 - 核心动画(转)

    iOS基础 - 核心动画 一、核心动画 l核心动画基本概念 l基本动画 l关键帧动画 l动画组 l转场动画 lCo...

  • iOS核心动画高级技巧 - 8

    iOS核心动画高级技巧 - 1iOS核心动画高级技巧 - 2iOS核心动画高级技巧 - 3iOS核心动画高级技巧 ...

  • iOS动画(Core Animation)

    1.核心动画(Core Animation):强大的动画API 核心动画所在的位置如下图 核心动画位于UIKit的...

  • IOS 常用动画的实现方式整理

    一、CoreAnimation(核心动画) 1.核心动画介绍 1.什么是核心动画 Core Animation可以...

  • UIview动画和核心动画的区别

    UIView和核心动画的区别 核心动画只能添加到CALayer,UIView没有办法使用核心动画 核心动画一切都是...

  • iOS-核心动画

    前言:核心动画的基础知识,包括基本动画、帧动画、转场动画相关知识。 一、核心动画(Core Animation) ...

  • iOS面试个人总结(1)

    动画 1.UIView动画与核心动画的区别? 核心动画只作用在layer. 核心动画修改的值都是假像.它的真实位置...

  • 再来看看动画

    动画一般有:UIKit动画和CoreAnimation(核心)动画 下面主要是核心动画的内容:http://www...

网友评论

      本文标题:16-核心动画

      本文链接:https://www.haomeiwen.com/subject/ntwelttx.html