iOS动画总结

iOS--Animation总结

UIKit框架中

1.UIImageView里的序列帧动画

  • 将序列帧动画图片存入imageView.animationImages数组中

示例:

NSMutableArray * array = [NSMutableArray array];

for (int i = 1; i < 6; i++) {
    //将图片存入数组
    NSString * string = [NSString stringWithFormat:@"hehua0%d",i];
    UIImage * image = [UIImage imageNamed:string];
    [array addObject:image];
}

self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
//设置动画图片
self.imageView.animationImages = array;
//动画时间
self.imageView.animationDuration = 1;
//动画播放重复次数,值为0时,无限循环
self.imageView.animationRepeatCount = 0;
//开始动画
[self.imageView startAnimating];
//结束动画
[self.imageView stopAnimating];
  • 播放GIF动画

可为UIImageView添加类别来实现方法

如+ (UIImageView *)imageViewWithGIFFile:(NSString *)file frame:(CGRect)frame;

导入头文件<ImageIO/ImageIO.h>和<CoreText/CoreText.h>

   /**
   * ARC下需要手动管理内存的有(Core)
   *CT开头,例如:CTRunRef
   *CF开头,例如:CTFrameRef
   *CG开头,例如:CGImageSourceRef
   */

  @implementation UIImageView (GIF)

  + (UIImageView *)imageViewWithGIFFile:(NSString *)file frame:(CGRect)frame
  {
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:frame];
    // 加载gif文件数据
    NSData *gifData = [NSData dataWithContentsOfFile:file];
    
    // GIF动画图片数组
    NSMutableArray *frames = nil;
    // 图像源引用
    CGImageSourceRef src = CGImageSourceCreateWithData((__bridge CFDataRef)gifData, NULL);
    // 动画时长
    CGFloat animationTime = 0.f;
    
    if (src) {
        // 获取gif图片的帧数
        size_t count = CGImageSourceGetCount(src);
        // 实例化图片数组
        frames = [NSMutableArray arrayWithCapacity:count];
        
        for (size_t i = 0; i < count; i++) {
            // 获取指定帧图像
            CGImageRef image = CGImageSourceCreateImageAtIndex(src, i, NULL);
            
            // 获取GIF动画时长
            NSDictionary *properties = (__bridge NSDictionary *)CGImageSourceCopyPropertiesAtIndex(src, i, NULL);
            NSDictionary *frameProperties = [properties objectForKey:(NSString *)kCGImagePropertyGIFDictionary];
            NSNumber *delayTime = [frameProperties objectForKey:(NSString *)kCGImagePropertyGIFUnclampedDelayTime];
            animationTime += [delayTime floatValue];
            
            if (image) {
                [frames addObject:[UIImage imageWithCGImage:image]];
                CGImageRelease(image);
            }
        }
        
        CFRelease(src);
    }
    
    [imageView setImage:[frames objectAtIndex:0]];
    [imageView setBackgroundColor:[UIColor clearColor]];
    [imageView setAnimationImages:frames];
    [imageView setAnimationDuration:animationTime];
    [imageView startAnimating];
    
    return imageView;
  }

2.UIView动画

  • 简单动画

    //开始动画
    [UIView beginAnimations:@"自定义动画名称" context:nil];
    //延迟2秒执行
    //[UIView setAnimationDelay:2];
    //设置动画时间
    [UIView setAnimationDuration:1];
    //设置动画代理
    [UIView setAnimationDelegate:self];
    //将要开始动画
    [UIView setAnimationWillStartSelector:@selector(要开始动画时执行)];
    //已经结束动画
    [UIView setAnimationDidStopSelector:@selector(结束动画执行)];
    //设置动画的速度变化
    [UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
    //设置重复次数
    //[UIView setAnimationRepeatCount:3];
    //动画的反转
    //[UIView setAnimationRepeatAutoreverses:YES];
    
    //设置UIView的位置变化,大小变化,透明度
    
    //    self.imageView.alpha = 0;
    //    self.testView.backgroundColor = [UIColor redColor];
    //
    //    distantce += 20;
    //
    //    self.testView.frame = CGRectMake(distantce, 0, 100, 100);
    
    //拉伸
    // self.testView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    //平移
    //    self.testView.transform = CGAffineTransformMakeTranslation(100, 100);
    //    self.testView.transform = CGAffineTransformTranslate(self.testView.transform, 20, 0);
    
    //旋转
    //self.testView.transform = CGAffineTransformMakeRotation(M_PI_2);
    //self.testView.transform = CGAffineTransformRotate(self.testView.transform, M_PI_4/2);
    
    //提交动画
    [UIView commitAnimations];
  • 转场动画

(1)在一个UIView上添加两个imageView,然后设置动画

 [UIView beginAnimations:@"transition" context:nil];

 [UIView setAnimationDuration:2];
    
  //设置转场动画 
 [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.contentView cache:YES];
    
 [self.contentView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    
 [UIView commitAnimations];
    

(2)UIView block转场动画

secondView -> firstView

这个方法会作用于fromView的父视图,用于切换两个view,通过执行这个方法,会将formView从其父视图上移除,将toView重新粘在其父视图上,展现一个动画效果。

[UIView transitionFromView:self.secondView toView:self.firstView duration:2 options:UIViewAnimationOptionTransitionCurlUp completion:^(BOOL finished) {
        
 }];
    

转场动画的block实现

 [UIView transitionWithView:self.contentView duration:2 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
    //1.该方法可以实现两个页面的来回切换
    [self.contentView exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    
    //2.该方法只能实现一次转场动画
//  [self.firstView removeFromSuperview];
//  [self.contentView addSubview:self.secondView];
        
        
    } completion:^(BOOL finished) {
        
    }];

  • UIView的block动画

(1)简单block动画的实现

  例1 图片的透明度变化动画
  
   //Duration动画时间 animations里是要到达的状态,completion里是动画完成之后的代码块
    
 [UIView animateWithDuration:1 animations:^{
      self.imageView.alpha = 0;
    } completion:^(BOOL finished) {
            
        [UIView animateWithDuration:1 animations:^{
            
            self.imageView.alpha = 1;

        } completion:^(BOOL finished) {
           
        }];
  }];

例2 图片的旋转变化动画

[UIView animateWithDuration:1 animations:^{
        
        self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, M_PI_2);
        
    } completion:^(BOOL finished) {
        
        [UIView animateWithDuration:1 animations:^{
            //下面是实现图片旋转一定度数后返回原位置的两种方法
            self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, -M_PI_2);
            
            //CGAffineTransformIdentity恢复最初状态
//            self.imageView.transform = CGAffineTransformIdentity;

        }];
        
    }];

例3 增加了动画延迟

    [UIView animateWithDuration:1 delay:2 options:UIViewAnimationOptionCurveEaseOut animations:^{
        self.imageView.backgroundColor = [UIColor grayColor];
    } completion:^(BOOL finished) {
        
    }];


(2) 带弹性效果的动画

    //Damping 弹力 0 ~ 1  
    //SpringVelocity 弹簧初速度
    
   [UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:10 options:UIViewAnimationOptionCurveLinear animations:^{

        self.imageView.frame = CGRectMake(200, 100, 100, 100);
        
    } completion:^(BOOL finished) {
        
    }];

(3)关键帧动画

    [UIView animateKeyframesWithDuration:3.0 delay:0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
        
        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1/6.0 animations:^{
            self.imageView.backgroundColor = [UIColor redColor];
        }];
        
        [UIView addKeyframeWithRelativeStartTime:1/6.0 relativeDuration:3/6.0 animations:^{
            self.imageView.backgroundColor = [UIColor blueColor];
        }];
        
        [UIView addKeyframeWithRelativeStartTime:4/6.0 relativeDuration:2/6.0 animations:^{
            self.imageView.backgroundColor = [UIColor orangeColor];
        }];
        
        
    } completion:^(BOOL finished) {
        
    }];


QuartzCore框架中

3.CALayer的隐式动画

  • 什么时候使用CALayer,什么时候使用UIView?

    当视图需要响应时使用UIView,仅作为展示使用CALayer.

    隐式动画只存在于CALayer的子层上

    CALayer * layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor greenColor].CGColor;
    
    layer.frame = CGRectMake(100, 100, 100, 100);

    [self.view.layer addSublayer:layer];


    //当执行layer变化语句时,默认有动画,即隐式动画
    _layer.frame = CGRectMake(100, 100, arc4random_uniform(100), arc4random_uniform(100));

4.核心动画Core Animation

?核心动画和UIView动画的区别

 核心动画一切都是假象,并不会真实的改变图层的属性值,如果以后做动画的时候,不需要与用户交互,通常用核心动画(转场)

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

CAAnimation是一个抽象类,mac,iOS 通用,遵循了CAMediaTiming协议和CAAction协议!我们不要直接使用CAAnimation类,而是使用其子类:

具体可看 http://www.henishuo.com/caanimation-indtroduce-in-detail/

CAAnimation(父类) -> CAPropertyAnimation 属性动画 -> (CABasicAnimation 基础动画 ,CAKeyframeAnimation 关键帧动画)

CAAnimation -> CAAnimationGroup 动画组

  • CABasicAnimation基础动画

    //创建基础动画
    CABasicAnimation * basic = [CABasicAnimation animation];
    //动画路径
    basic.keyPath = @"position";
    
    //绝对距离
    //设置初始状态
//    basic.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];
    //终止状态
//    basic.toValue = [NSValue valueWithCGPoint:CGPointMake(300, 300)];
    
    //动画距离(相对距离)
    //basic.byValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)];
    
    //动画的初始和结束的模式 fillMode和removedOnCompletion要配合使用
    basic.fillMode = kCAFillModeForwards;// @"forwards";
    //动画完成在layer中删除
    basic.removedOnCompletion = NO;
    
    //如果初始状态就是当前动画未执行的位置
    
    //动画时间
    basic.duration = 1;
    
    //动画的速度变化 eg:kCAMediaTimingFunctionEaseIn越来越快
    basic.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    //?
    //animation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.5 :0 :0.9 :0.7];

    
    //添加动画
    [_animationView.layer addAnimation:basic forKey:@"basic"];


  • CAKeyframeAnimation 关键帧动画

    //创建关键帧动画
    CAKeyframeAnimation * keyframe = [CAKeyframeAnimation animation];
    
    keyframe.keyPath = @"position.x";
    
    //设置关键帧的位置
    keyframe.values = @[@0,@10,@-10,@10,@0];

    //设置关键帧的时间
    keyframe.keyTimes = @[ @0, @(1 / 6.0), @(3 / 6.0), @(5 / 6.0), @1 ];
    
    //无需设置起始位置
    keyframe.additive = YES;
    
    //calculationMode设置加速度,kCAAnimationPaced保持恒定的加速度,如果设置calculationMode,keyTimes失效
    keyframe.calculationMode = kCAAnimationPaced;
    
    //设置时间
    keyframe.duration = 0.5;
    
    [_animationView.layer addAnimation:keyframe forKey:@"keyframe"];

利用贝塞尔

    UIView * v = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 30, 30)];
    v.backgroundColor = [UIColor grayColor];
    [self.view addSubview:v];

    UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 300, 300)];
    
    //创建关键帧动画
    CAKeyframeAnimation * keyframe = [CAKeyframeAnimation animation];
    
    keyframe.keyPath = @"position";
    
    keyframe.path = path.CGPath;
    
    //设置时间
    keyframe.duration = 2;
    
    //重复次数
    keyframe.repeatCount = HUGE_VALF; //MAXFLOAT;
    
    [_animationView.layer addAnimation:keyframe forKey:@"keyframe"];

  • CAAnimationGroup动画组

    CABasicAnimation * basic1 = [CABasicAnimation animation];
    basic1.keyPath = @"transform.scale";
    basic1.toValue = @(arc4random_uniform(5));
    basic1.duration = 0.5;
    basic1.removedOnCompletion = NO;
    basic1.fillMode = @"forwards";
//    [self.animationView.layer addAnimation:basic1 forKey:@"aaa"];
    
    CABasicAnimation * basic2 = [CABasicAnimation animation];
    basic2.keyPath = @"transform.rotation";
    basic2.toValue = @(arc4random_uniform(M_PI));
    basic2.duration = 0.5;
    basic2.beginTime = 0.5;
    
//    [self.animationView.layer addAnimation:basic2 forKey:nil];

    CAAnimationGroup * group = [CAAnimationGroup animation];
    
    group.duration = 1;
    group.removedOnCompletion = NO;
    group.fillMode = @"forwards";

    group.animations = @[basic1,basic2];
    
    [self.animationView.layer addAnimation:group forKey:nil];

  • CATransition过渡动画

设置视图变化时的动画效果

  • 1.#define定义的常量

    • kCATransitionFade 交叉淡化过渡

    • kCATransitionMoveIn 新视图移到旧视图上面

    • kCATransitionPush 新视图把旧视图推出去

    • kCATransitionReveal 将旧视图移开,显示下面的新视图

  • 2.用字符串表示

    • pageCurl 向上翻一页

    • pageUnCurl 向下翻一页

    • rippleEffect 滴水效果

    • suckEffect 收缩效果,如一块布被抽走

    • cube 立方体效果

    • oglFlip 上下翻转效果

    CATransition * transition = [CATransition animation];
    transition.type = @"suckEffect";
    transition.subtype = @"fromLeft";
    transition.duration = 2;
    [self.imageView.layer addAnimation:transition forKey:nil];

//CADisplayLink,selector每秒钟默认调用60次。

//CADisplayLink和NSTimer区别:CADisplayLink用来做绘图,重绘。NSTimer用于计时,重复调用。

 //创建CADisplayLink
   self.displaylink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleAction:)];
   
   //调用次数 = 60 / frameInterval
//    self.displaylink.frameInterval = 3;
   
   //将CADisplayLink放入RunLoop里
   [self.displaylink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

Facebook POP动画

  • poping开源库

POP比较好的一点是保留了动画结束后的状态,通过block回调。使用POPAnimatableProperty 可以快速添加基本动画,也可以自定义属性动画。

---弹性动画---

- (void)spring{

    POPSpringAnimation* framePOP = [POPSpringAnimation animationWithPropertyNamed:kPOPViewBackgroundColor];

    framePOP.springSpeed = 10.f;

    framePOP.springBounciness = 4.f;

    framePOP.toValue = [UIColor greenColor];

    [framePOP setCompletionBlock:^(POPAnimation * anim , BOOL finsih) {

        if (finsih) {

            NSLog(@"view.frame = %@",NSStringFromCGRect(view.frame));

        }

    }];

    [view pop_addAnimation:framePOP forKey:@"go"];

}

---减缓动画——--

- (void)Decay{

    POPDecayAnimation* decay = [POPDecayAnimation animationWithPropertyNamed:kPOPViewFrame];

// decay.toValue = [NSValue valueWithCGRect:CGRectMake(200, 400, 100, 100)];

    decay.velocity = [NSValue valueWithCGRect:CGRectMake(200, 300, 100, 100)];

    [view pop_addAnimation:decay forKey:@"go"];
}

---基本动画---

-(void)basic{

    POPBasicAnimation* basicAnimation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerCornerRadius];

    basicAnimation.toValue = [NSNumber numberWithFloat:CGRectGetHeight(view.frame)/2.];

    basicAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

// basicAnimation.duration = 3.f;

    [basicAnimation setCompletionBlock:^(POPAnimation * ani, BOOL fin) {

        if (fin) {

            NSLog(@"view.frame = %@",NSStringFromCGRect(view.frame));

// POPBasicAnimation* newBasic = [POPBasicAnimation easeInEaseOutAnimation];

// newBasic.property = [POPAnimatableProperty propertyWithName:kPOPLayerCornerRadius];

// newBasic.toValue = [NSNumber numberWithFloat:0];

// [view.layer pop_addAnimation:newBasic forKey:@"go"];

        }

    }];

    [view.layer pop_addAnimation:basicAnimation forKey:@"frameChange"];

---组合动画---

-(void)group
{

    view.transform = CGAffineTransformMakeRotation(M_PI_2/3);

    POPBasicAnimation* spring = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionY];

    spring.beginTime = CACurrentMediaTime();

    spring.duration = .4f;

    spring.fromValue = [NSNumber numberWithFloat:-100.f];

    spring.toValue = [NSNumber numberWithFloat:CGRectGetMinY(view.frame) + 80];

    [spring setCompletionBlock:^(POPAnimation * ani, BOOL fin) {

    }];

    POPBasicAnimation* basic = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotation];

    basic.beginTime = CACurrentMediaTime();

    basic.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    basic.toValue = [NSNumber numberWithFloat:-M_PI_4];

    basic.duration = .4f;

    POPBasicAnimation* rotation = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerRotation];

    rotation.beginTime = CACurrentMediaTime() + .4f;

    rotation.toValue = [NSNumber numberWithFloat:0.f];

    rotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    rotation.duration = .25f;

    POPBasicAnimation* donw = [POPBasicAnimation animationWithPropertyNamed:kPOPLayerPositionY];

    donw.beginTime = CACurrentMediaTime() + 0.4f;

    donw.toValue = [NSNumber numberWithFloat:CGRectGetMinY(view.frame)];

    donw.duration = .25f;

    donw.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];

    [view.layer pop_addAnimation:spring forKey:@"spring"];

    [view.layer pop_addAnimation:basic forKey:@"basic"];

    [view.layer pop_addAnimation:donw forKey:@"down"];

    [view.layer pop_addAnimation:rotation forKey:@"rotation"];

}


原文地址:https://www.cnblogs.com/xiaonan-net/p/5483812.html