前语

咱们在前面,首要进行了针对 iOS中的多媒体技能相关几个结构概述:

  1. 进而 用 两篇文章 对 其中的 UIKit相关关键 进行了分述:
  2. 咱们 在此篇文章 ,将 针对 Core Animation结构的关键 进一步展开分述:

一、 iOS 中 动画完结的几种办法

  • UIKit动画
  • Core Animation动画
    • CAAnimationGroup
    • CATransaction
    • CAPropertyAnimation
      • CAKeyframeAnimation
      • CABasicAnimation
        • CASpringAnimation
  • UIImageView帧动画
  • 经典第三方动画库

二、UIKit动画

1. 可动画特色:

UIView动画能够设置的动画特色有:

  • frame
  • bounds
  • center
  • transform
  • alpha
  • backgroundColor
  • contentStretch

UIView动画支撑几种动画类型,一般 对View的可动画特色的修正增加动画,直接用 Block动画就足够了

2. 一般动画

开端动画句子:

// 第一个参数: 动画标识
// 第二个参数: 附加参数,在设置署理状况下,此参数将发送到setAnimationWillStartSelector和setAnimationDidStopSelector所指定的办法,大部分状况,设置为nil.
[UIView beginAnimations:(nullable NSString *) context:(nullable void *)];

完毕动画句子:

[UIView commitAnimations];

动画参数的特色设置:

//动画继续时刻
[UIView setAnimationDuration:(NSTimeInterval)];
//动画的署理目标 
[UIView setAnimationDelegate:(nullable id)];
//设置动画将开端时署理目标履行的SEL
[UIView setAnimationWillStartSelector:(nullable SEL)];
//设置动画推迟履行的时刻
[UIView setAnimationDelay:(NSTimeInterval)];
//设置动画的重复次数
[UIView setAnimationRepeatCount:(float)];
//设置动画的曲线
/*
UIViewAnimationCurve的枚举值:
UIViewAnimationCurveEaseInOut,         // 慢进慢出(默许值)
UIViewAnimationCurveEaseIn,            // 慢进
UIViewAnimationCurveEaseOut,           // 慢出
UIViewAnimationCurveLinear             // 匀速
*/
[UIView setAnimationCurve:(UIViewAnimationCurve)];
//设置是否从当时状况开端播映动画
/*假设上一个动画正在播映,且尚未播映完毕,咱们即将进行一个新的动画:
当为YES时:动画将从上一个动画所在的状况开端播映
当为NO时:动画将从上一个动画所指定的终究状况开端播映(此时上一个动画立刻完毕)*/
[UIView setAnimationBeginsFromCurrentState:YES];
//设置动画是否继续履行相反的动画
[UIView setAnimationRepeatAutoreverses:(BOOL)];
//是否禁用动画作用(目标特色仍然会被改动,仅仅没有动画作用)
[UIView setAnimationsEnabled:(BOOL)];
//设置视图的过渡作用
/* 第一个参数:UIViewAnimationTransition的枚举值如下
     UIViewAnimationTransitionNone,              //不运用动画
     UIViewAnimationTransitionFlipFromLeft,      //从左向右旋转翻页
     UIViewAnimationTransitionFlipFromRight,     //从右向左旋转翻页
     UIViewAnimationTransitionCurlUp,            //从下往上弯曲翻页
     UIViewAnimationTransitionCurlDown,          //从上往下弯曲翻页
 第二个参数:需求过渡作用的View
 第三个参数:是否运用视图缓存,YES:视图在开端和完毕时烘托一次;NO:视图在每一帧都烘托*/
[UIView setAnimationTransition:(UIViewAnimationTransition) forView:(nonnull UIView *) cache:(BOOL)];

更详细的API阐明:

/** 动画的曲线枚举 */
typedef NS_ENUM(NSInteger, UIViewAnimationCurve) {
    UIViewAnimationCurveEaseInOut,  //!< 慢进慢出(默许值).
    UIViewAnimationCurveEaseIn,     //!< 慢进.
    UIViewAnimationCurveEaseOut,    //!< 慢出.
    UIViewAnimationCurveLinear,     //!< 匀速.
};
/** UIView动画过渡作用 */
typedef NS_ENUM(NSInteger, UIViewAnimationTransition) {
    UIViewAnimationTransitionNone,          //!< 无作用.
    UIViewAnimationTransitionFlipFromLeft,  //!< 沿视图笔直中心轴左到右移动.
    UIViewAnimationTransitionFlipFromRight, //!< 沿视图笔直中心轴右到左移动.
    UIViewAnimationTransitionCurlUp,        //!< 由底部向上卷起.
    UIViewAnimationTransitionCurlDown,      //!< 由顶部向下展开.
};
@interface UIView(UIViewAnimation)
/** 开端动画 */
+ (void)beginAnimations:(nullable NSString *)animationID context:(nullable void *)context;
/** 提交动画 */
+ (void)commitAnimations;
/** 设置动画署理, 默许nil */
+ (void)setAnimationDelegate:(nullable id)delegate;
/** 动画即将开端时履行办法(必需求先设置动画署理), 默许NULL */
+ (void)setAnimationWillStartSelector:(nullable SEL)selector;
/** 动画已完毕时履行办法(必需求先设置动画署理), 默许NULL */
+ (void)setAnimationDidStopSelector:(nullable SEL)selector;
/** 设置动画时长, 默许0.2秒 */
+ (void)setAnimationDuration:(NSTimeInterval)duration;
/** 动画推迟履行时刻, 默许0.0秒 */
+ (void)setAnimationDelay:(NSTimeInterval)delay;
/** 设置在动画块内部动画特色改动的开端时刻, 默许now ([NSDate date]) */
+ (void)setAnimationStartDate:(NSDate *)startDate;
/** 设置动画曲线, 默许UIViewAnimationCurveEaseInOut */
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;
/** 动画的重复播映次数, 默许0 */
+ (void)setAnimationRepeatCount:(float)repeatCount;
/** 设置是否自定翻转当时的动画作用, 默许NO */
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses;
/** 设置动画从当时状况开端播映, 默许NO */
+ (void)setAnimationBeginsFromCurrentState:(BOOL)fromCurrentState;
/** 在动画块中为视图设置过渡动画 */
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;
/** 设置是否激活动画 */
+ (void)setAnimationsEnabled:(BOOL)enabled;
/** 回来一个布尔值表明动画是否完毕 */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) BOOL areAnimationsEnabled;
#else
+ (BOOL)areAnimationsEnabled;
#endif
/** 先检查动画当时是否启用,然后禁止动画,履行block内的办法,终究从头启用动画,而且这个办法不会阻塞依据CoreAnimation的动画 */
+ (void)performWithoutAnimation:(void (NS_NOESCAPE ^)(void))actionsWithoutAnimation NS_AVAILABLE_IOS(7_0);
/** 当时动画的继续时刻 */
#if UIKIT_DEFINE_AS_PROPERTIES
@property(class, nonatomic, readonly) NSTimeInterval inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#else
+ (NSTimeInterval)inheritedAnimationDuration NS_AVAILABLE_IOS(9_0);
#endif
@end

Demo示例1:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch *tuch = touches.anyObject;
    CGPoint point = [tuch locationInView:self.view];
    [UIView beginAnimations:@"testAnimation" context:nil];
    [UIView setAnimationDuration:3.0];
    [UIView setAnimationDelegate:self];
    //设置动画将开端时署理目标履行的SEL
    [UIView setAnimationWillStartSelector:@selector(animationDoing)];
    //设置动画推迟履行的时刻
    [UIView setAnimationDelay:0];
    [UIView setAnimationRepeatCount:MAXFLOAT];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    //设置动画是否继续履行相反的动画
    [UIView setAnimationRepeatAutoreverses:YES];
    self.redView.center = point;
    self.redView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.redView.transform = CGAffineTransformMakeRotation(M_PI);
    [UIView commitAnimations];
}

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

Demo示例2:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    UITouch *tuch = touches.anyObject;
    CGPoint point = [tuch locationInView:self.view];
    [UIView beginAnimations:@"testAnimation" context:nil];
    [UIView setAnimationDuration:3.0];
    [UIView setAnimationDelegate:self];
    //设置动画将开端时署理目标履行的SEL
    [UIView setAnimationWillStartSelector:@selector(animationDoing)];
    //设置动画推迟履行的时刻
    [UIView setAnimationDelay:0];
    [UIView setAnimationRepeatCount:MAXFLOAT];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];
    //设置动画是否继续履行相反的动画
    [UIView setAnimationRepeatAutoreverses:YES];
    self.redView.center = point;
    self.redView.transform = CGAffineTransformMakeScale(1.5, 1.5);
    self.redView.transform = CGAffineTransformMakeRotation(M_PI);
    [UIView commitAnimations];
}

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

Demo示例3:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    // 转成动画 (flip)
    [UIView beginAnimations:@"imageViewTranslation" context:nil];
    [UIView setAnimationDuration:2.0];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationWillStartSelector:@selector(startAnimation)];
    [UIView setAnimationDidStopSelector:@selector(stopAnimation)];
    [UIView setAnimationRepeatCount:1.0];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationRepeatAutoreverses:YES];
    [UIView setAnimationRepeatCount:MAXFLOAT];
    [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.imageView cache:YES];
    if (++count % 2 ==0) {
        self.imageView.image = [UIImage imageNamed:@"yh_detial_ty"];
    }else{
        self.imageView.image = [UIImage imageNamed:@"yh_detial_bz"];
    }
    [UIView commitAnimations];
}

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

3. block动画

iOS4.0以后增加了Block动画块,供给了更简洁的办法来完结动画.日常开发中一般也是运用Block办法创立动画。

最简洁的Block动画:包含时刻动画:

[UIView animateWithDuration:(NSTimeInterval)  //动画继续时刻
              animations:^{
              //履行的动画
 }];

带有动画提交回调的Block动画

 [UIView animateWithDuration:(NSTimeInterval)  //动画继续时刻
              animations:^{
            //履行的动画
 }                completion:^(BOOL finished) {
            //动画履行提交后的操作
 }];

能够设置延时时刻和过渡作用的Block动画

[UIView animateWithDuration:(NSTimeInterval) //动画继续时刻
                   delay:(NSTimeInterval) //动画推迟履行的时刻
                 options:(UIViewAnimationOptions) //动画的过渡作用
              animations:^{
               //履行的动画
 }                completion:^(BOOL finished) {
               //动画履行提交后的操作
 }];

UIViewAnimationOptions的枚举值如下,可组合运用:

 UIViewAnimationOptionLayoutSubviews            //进行动画时布局子控件
 UIViewAnimationOptionAllowUserInteraction      //进行动画时答运用户交互
 UIViewAnimationOptionBeginFromCurrentState     //从当时状况开端动画
 UIViewAnimationOptionRepeat                    //无限重复履行动画
 UIViewAnimationOptionAutoreverse               //履行动画回路
 UIViewAnimationOptionOverrideInheritedDuration //疏忽嵌套动画的履行时刻设置
 UIViewAnimationOptionOverrideInheritedCurve    //疏忽嵌套动画的曲线设置
 UIViewAnimationOptionAllowAnimatedContent      //转场:进行动画时重绘视图
 UIViewAnimationOptionShowHideTransitionViews   //转场:移除(增加和移除图层的)动画作用
 UIViewAnimationOptionOverrideInheritedOptions  //不承继父动画设置
 UIViewAnimationOptionCurveEaseInOut            //时刻曲线,慢进慢出(默许值)
 UIViewAnimationOptionCurveEaseIn               //时刻曲线,慢进
 UIViewAnimationOptionCurveEaseOut              //时刻曲线,慢出
 UIViewAnimationOptionCurveLinear               //时刻曲线,匀速
 UIViewAnimationOptionTransitionNone            //转场,不运用动画
 UIViewAnimationOptionTransitionFlipFromLeft    //转场,从左向右旋转翻页
 UIViewAnimationOptionTransitionFlipFromRight   //转场,从右向左旋转翻页
 UIViewAnimationOptionTransitionCurlUp          //转场,下往上弯曲翻页
 UIViewAnimationOptionTransitionCurlDown        //转场,从上往下弯曲翻页
 UIViewAnimationOptionTransitionCrossDissolve   //转场,穿插消失和出现
 UIViewAnimationOptionTransitionFlipFromTop     //转场,从上向下旋转翻页
 UIViewAnimationOptionTransitionFlipFromBottom  //转场,从下向上旋转翻页

Spring动画

iOS7.0以后新增了Spring动画(IOS体系动画大部分选用Spring Animation, 适用一切可被增加动画作用的特色)

 [UIView animateWithDuration:(NSTimeInterval)//动画继续时刻
                   delay:(NSTimeInterval)//动画推迟履行的时刻
  usingSpringWithDamping:(CGFloat)//震动作用,规模0~1,数值越小震动作用越显着
   initialSpringVelocity:(CGFloat)//初始速度,数值越大初始速度越快
                 options:(UIViewAnimationOptions)//动画的过渡作用
              animations:^{
                 //履行的动画
 }
                  completion:^(BOOL finished) {
                 //动画履行提交后的操作
 }];

更详细的API阐明:


/** UIView动画选项 */
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
    UIViewAnimationOptionLayoutSubviews            = 1 <<  0, //!< 动画进程中确保子视图跟随运动.
    UIViewAnimationOptionAllowUserInteraction      = 1 <<  1, //!< 动画进程中答运用户交互.
    UIViewAnimationOptionBeginFromCurrentState     = 1 <<  2, //!< 一切视图从当时状况开端运转.
    UIViewAnimationOptionRepeat                    = 1 <<  3, //!< 重复运转动画.
    UIViewAnimationOptionAutoreverse               = 1 <<  4, //!< 动画运转到完毕点后仍然以动画办法回到初始点.
    UIViewAnimationOptionOverrideInheritedDuration = 1 <<  5, //!< 疏忽嵌套动画时刻设置.
    UIViewAnimationOptionOverrideInheritedCurve    = 1 <<  6, //!< 疏忽嵌套动画速度设置.
    UIViewAnimationOptionAllowAnimatedContent      = 1 <<  7, //!< 动画进程中重绘视图(留意仅仅适用于转场动画).
    UIViewAnimationOptionShowHideTransitionViews   = 1 <<  8, //!< 视图切换时直接躲藏旧视图、显现新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画).
    UIViewAnimationOptionOverrideInheritedOptions  = 1 <<  9, //!< 不承继父动画设置或动画类型.
    UIViewAnimationOptionCurveEaseInOut            = 0 << 16, //!< 动画先缓慢,然后逐步加快.
    UIViewAnimationOptionCurveEaseIn               = 1 << 16, //!< 动画逐步变慢.
    UIViewAnimationOptionCurveEaseOut              = 2 << 16, //!< 动画逐步加快.
    UIViewAnimationOptionCurveLinear               = 3 << 16, //!< 动画匀速履行,默许值.
    UIViewAnimationOptionTransitionNone            = 0 << 20, //!< 没有转场动画作用.
    UIViewAnimationOptionTransitionFlipFromLeft    = 1 << 20, //!< 从左侧翻转作用.
    UIViewAnimationOptionTransitionFlipFromRight   = 2 << 20, //!< 从右侧翻转作用.
    UIViewAnimationOptionTransitionCurlUp          = 3 << 20, //!< 向后翻页的动画过渡作用.
    UIViewAnimationOptionTransitionCurlDown        = 4 << 20, //!< 向前翻页的动画过渡作用.
    UIViewAnimationOptionTransitionCrossDissolve   = 5 << 20, //!< 旧视图溶解消失显现下一个新视图的作用.
    UIViewAnimationOptionTransitionFlipFromTop     = 6 << 20, //!< 从上方翻转作用.
    UIViewAnimationOptionTransitionFlipFromBottom  = 7 << 20, //!< 从底部翻转作用.
    UIViewAnimationOptionPreferredFramesPerSecondDefault     = 0 << 24, //!< 默许的帧每秒.
    UIViewAnimationOptionPreferredFramesPerSecond60          = 3 << 24, //!< 60帧每秒的帧速率.
    UIViewAnimationOptionPreferredFramesPerSecond30          = 7 << 24, //!< 30帧每秒的帧速率.
} NS_ENUM_AVAILABLE_IOS(4_0);
@interface UIView(UIViewAnimationWithBlocks)
/** 用于对一个或多个视图的改动的继续时刻、延时、选项动画完结时的操作 */
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
/** 用于对一个或多个视图的改动的继续时刻、选项动画完结时的操作,默许:delay = 0.0, options = 0 */
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
/** 用于对一个或多个视图的改动的继续时刻内动画完结时的操作,默许:delay = 0.0, options = 0, completion = NULL */
+ (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations NS_AVAILABLE_IOS(4_0);
/** 运用与物理弹簧运动相对应的定时曲线履行视图动画 */
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
/** 为指定的容器视图创立转化动画 */
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0);
/** 运用给定的参数在指定视图之间创立转化动画 */
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(4_0); // toView added to fromView.superview, fromView removed from its superview
/** 在一个或多个视图上履行指定的体系供给的动画,以及界说的可选并行动画 */
+ (void)performSystemAnimation:(UISystemAnimation)animation onViews:(NSArray<__kindof UIView *> *)views options:(UIViewAnimationOptions)options animations:(void (^ __nullable)(void))parallelAnimations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
@end

Demo示例1

[UIView animateWithDuration:3.0 animations:^{
        self.redView.center = point;
        self.redView.transform = CGAffineTransformMakeScale(1.5, 1.5);
        self.redView.transform = CGAffineTransformMakeRotation(M_PI);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:2.0 animations:^{
            self.redView.frame = CGRectMake(100, 100, 100, 100);
            self.redView.transform = CGAffineTransformMakeScale(1 / 1.5,1 / 1.5);
            self.redView.transform = CGAffineTransformMakeRotation(M_PI);
        }];
    }];

Demo示例2

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    self.redView.alpha = 0;
/*
animateWithDuration 动画继续时刻
delay 动画推迟履行的时刻
usingSpringWithDamping 震动作用,规模0~1,数值越小震动作用越显着
initialSpringVelocity 初始速度,数值越大初始速度越快
options 动画的过渡作用
*/
    [UIView animateWithDuration:3.0  delay:1.0 usingSpringWithDamping:0.3 initialSpringVelocity:1 options:UIViewAnimationOptionAllowUserInteraction animations:^{
        self.redView.alpha = 1.0;
        self.redView.frame = CGRectMake(200, 350, 140, 140);
    } completion:^(BOOL finished) {
        [self.redView removeFromSuperview];
    }];
}

4. 关键帧动画

IOS7.0后新增了关键帧动画,支撑特色关键帧,不支撑途径关键帧

 [UIView animateKeyframesWithDuration:(NSTimeInterval)//动画继续时刻
                            delay:(NSTimeInterval)//动画推迟履行的时刻
                          options:(UIViewKeyframeAnimationOptions)//动画的过渡作用
                       animations:^{
                     //履行的关键帧动画
 }
                       completion:^(BOOL finished) {
                     //动画履行提交后的操作
 }];

UIViewKeyframeAnimationOptions的枚举值如下,可组合运用:

UIViewAnimationOptionLayoutSubviews           //进行动画时布局子控件
UIViewAnimationOptionAllowUserInteraction     //进行动画时答运用户交互
UIViewAnimationOptionBeginFromCurrentState    //从当时状况开端动画
UIViewAnimationOptionRepeat                   //无限重复履行动画
UIViewAnimationOptionAutoreverse              //履行动画回路
UIViewAnimationOptionOverrideInheritedDuration //疏忽嵌套动画的履行时刻设置
UIViewAnimationOptionOverrideInheritedOptions //不承继父动画设置
UIViewKeyframeAnimationOptionCalculationModeLinear     //运算办法 :接连
UIViewKeyframeAnimationOptionCalculationModeDiscrete   //运算办法 :离散
UIViewKeyframeAnimationOptionCalculationModePaced      //运算办法 :均匀履行
UIViewKeyframeAnimationOptionCalculationModeCubic      //运算办法 :滑润
UIViewKeyframeAnimationOptionCalculationModeCubicPaced //运算办法 :滑润均匀

各种运算办法的直观比较如下图:

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

增加关键帧办法:

[UIView addKeyframeWithRelativeStartTime:(double)//动画开端的时刻(占总时刻的份额)
                     relativeDuration:(double) //动画继续时刻(占总时刻的份额)
                           animations:^{
                         //履行的动画
 }];

转场动画:
a.从旧视图到新视图的动画作用

[UIView transitionFromView:(nonnull UIView *) toView:(nonnull UIView *) duration:(NSTimeInterval) options:(UIViewAnimationOptions) completion:^(BOOL finished) {
                 //动画履行提交后的操作
 }];

在该动画进程中,fromView 会从父视图中移除,并将 toView 增加到父视图中,留意转场动画的作用目标是父视图(过渡作用体现在父视图上)。调用该办法相当于履行下面两句代码:

[fromView.superview addSubview:toView];
[fromView removeFromSuperview];

单个视图的过渡作用

[UIView transitionWithView:(nonnull UIView *)
               duration:(NSTimeInterval)
                options:(UIViewAnimationOptions)
             animations:^{
             //履行的动画
 }
             completion:^(BOOL finished) {
             //动画履行提交后的操作
 }];

更详细的API阐明:

typedef NS_OPTIONS(NSUInteger, UIViewKeyframeAnimationOptions) {
    UIViewKeyframeAnimationOptionLayoutSubviews            = UIViewAnimationOptionLayoutSubviews, //!< 动画进程中确保子视图跟随运动.
    UIViewKeyframeAnimationOptionAllowUserInteraction      = UIViewAnimationOptionAllowUserInteraction, //!< 动画进程中答运用户交互.
    UIViewKeyframeAnimationOptionBeginFromCurrentState     = UIViewAnimationOptionBeginFromCurrentState, //!< 一切视图从当时状况开端运转.
    UIViewKeyframeAnimationOptionRepeat                    = UIViewAnimationOptionRepeat, //!< 重复运转动画.
    UIViewKeyframeAnimationOptionAutoreverse               = UIViewAnimationOptionAutoreverse, //!< 动画运转到完毕点后仍然以动画办法回到初始点.
    UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration, //!< 疏忽嵌套动画时刻设置.
    UIViewKeyframeAnimationOptionOverrideInheritedOptions  = UIViewAnimationOptionOverrideInheritedOptions, //!< 不承继父动画设置或动画类型.
    UIViewKeyframeAnimationOptionCalculationModeLinear     = 0 << 10, //!< 接连运算办法, 默许.
    UIViewKeyframeAnimationOptionCalculationModeDiscrete   = 1 << 10, //!< 离散运算办法.
    UIViewKeyframeAnimationOptionCalculationModePaced      = 2 << 10, //!< 均匀履行运算办法.
    UIViewKeyframeAnimationOptionCalculationModeCubic      = 3 << 10, //!< 滑润运算办法.
    UIViewKeyframeAnimationOptionCalculationModeCubicPaced = 4 << 10  //!< 滑润均匀运算办法.
} NS_ENUM_AVAILABLE_IOS(7_0);
/** UIView的关键帧动画 */
@interface UIView (UIViewKeyframeAnimations)
/** 创立一个动画块目标,可用于为当时视图设置依据关键帧的动画 */
+ (void)animateKeyframesWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewKeyframeAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
/** 增加指定开端时刻、继续时刻的关键帧动画(开端和继续时刻是0.0和1.0之间的值) */
+ (void)addKeyframeWithRelativeStartTime:(double)frameStartTime relativeDuration:(double)frameDuration animations:(void (^)(void))animations NS_AVAILABLE_IOS(7_0);
@end

三、Core Animation动画

说到中心动画,那就不得不先说下 CALayer

  • 在iOS体系中,你能看得见摸得着的东西根本上都是UIView,比方一个按钮、一个文本标签、一个文本输入框、一个图标等等,这些都是UIView。
  • 其实UIView之所以能显现在屏幕上,彻底是由于它内部的一个layer目标。
  • 在创立UIView目标时,UIView内部会主动创立一个层(即CALayer目标),经过UIView的layer特色能够访问这个层。当UIView需求显现到屏幕上时,会调用drawRect:办法进行绘图,而且会将一切内容绘制在自己的层上,绘图完毕后,体系会将层复制到屏幕上,于是就完结了UIView的显现。
  • 换句话说,UIView本身不具有显现的功用,是它内部的层才有显现功用。

上面现已说过了,UIView之所以能够显现,彻底是由于内部的CALayer目标。因而,经过操作这个CALayer目标,能够很便利地调整UIView的一些界面特色,比方: 暗影、圆角巨细、边框宽度和色彩等。

1. CALayer的特色回忆

//下面是CALayer的一些特色介绍
//宽度和高度
@property CGRect bounds;
//方位(默许指中点,详细由anchorPoint决议)
@property CGPoint position;
//锚点(x,y的规模都是0-1),决议了position的意义
@property CGPoint anchorPoint;
//布景色彩(CGColorRef类型)
@propertyCGColorRefbackgroundColor;
//形变特色
@property CATransform3D transform;
//边框色彩(CGColorRef类型)
@property  CGColorRef  borderColor;
//边框宽度
@property CGFloat borderWidth;
//圆角半径
@property CGFloat cornerRadius;
//内容(比方设置为图片CGImageRef)
@property(retain) id contents;

2. 给CALayercontents赋值

阐明:能够经过设置contents特色给UIView设置布景图片,留意有必要是CGImage才能显现,咱们能够在UIImage目标后边加上.CGImage直接转化,转化之后还需求在前面加上(id)进行强转。

// 跨结构赋值需求进行桥接
self.view.layer.contents = (__bridge id _Nullable)([UIImage imageNamed:@"123"].CGImage); 

值得留意的是,UIView的CALayer目标(层)经过layer特色能够访问这个层。要留意的是,这个默许的层不答应从头创立,但能够往层里边增加子层。UIView能够经过addSubview:办法增加子视图,类似地,CALayer能够经过addSublayer:办法增加子层

3. position和anchorPoint

CALayer目标有两个比较重要的特色,那便是position和anchorPoint。

  • position和anchorPoint特色都是CGPoint类型的
  • position能够用来设置CALayer在父层中的方位,它是以父层的左上角为坐标原点(0, 0)
  • anchorPoint称为”锚点”,它决议着CALayer身上的哪个点会在position特色所指的方位。它的x、y取值规模都是0~1,默许值为(0.5, 0.5)
  1. 创立一个CALayer,增加到操控器的view的layer中
     CALayer *myLayer = [CALayer layer];
    // 设置层的宽度和高度(100x100)
    myLayer.bounds = CGRectMake(0, 0, 100, 100);
    // 设置层的方位
    myLayer.position = CGPointMake(100, 100);
    // 设置层的布景色彩:红色
    myLayer.backgroundColor = [UIColor redColor].CGColor;
    // 增加myLayer到操控器的view的layer中
    [self.view.layer addSublayer:myLayer];
    
    第5行设置了myLayer的position为(100, 100),又由于anchorPoint默许是(0.5, 0.5),所以终究的作用是:myLayer的中点会在父层的(100, 100)方位
    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

留意,蓝色线是我自己加上去的,便利大家了解,并不是默许的显现作用。两条蓝色线的宽度均为100。

  1. 若将anchorPoint改为(0, 0),myLayer的左上角会在(100, 100)方位
    myLayer.anchorPoint = CGPointMake(0, 0);

    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

  2. 若将anchorPoint改为(1, 1),myLayer的右下角会在(100, 100)方位
    myLayer.anchorPoint = CGPointMake(1, 1);

    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

  3. 将anchorPoint改为(0, 1),myLayer的左下角会在(100, 100)方位
    myLayer.anchorPoint = CGPointMake(0, 1);

    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

我想,你应该现已大概了解anchorPoint的用处了吧,它决议着CALayer身上的哪个点会在position所指定的方位上。它的x、y取值规模都是0~1,默许值为(0.5, 0.5),因而,默许状况下,CALayer的中点会在position所指定的方位上。当anchorPoint为其他值时,以此类推。
anchorPoint是视图的中心点,position是视图的方位,方位会和中心点重叠。所以咱们在开发中能够经过修正视图的layer.anchorPoint或许layer.position完结特定的动画作用。
下面举个两个比方: 两份代码,上面那个是anchorPoint为(0.5, 0.5)也便是默许状况下,下面那个是(0, 0)。

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

代码如下:

self.redView.layer.anchorPoint = CGPointMake(0.5, 0.5);
[UIView animateWithDuration:3.0 animations:^{
    self.redView.transform = CGAffineTransformMakeRotation(M_PI);
} completion:^(BOOL finished) {
}];

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

代码如下:

self.redView.layer.anchorPoint = CGPointMake(0, 0);
    [UIView animateWithDuration:3.0 animations:^{
        self.redView.transform = CGAffineTransformMakeRotation(M_PI);
    } completion:^(BOOL finished) {
    }];

4. CATransaction业务类|隐式动画

留意 CATransaction 不是 CATransition 根层与非根层:

  • 每一个UIView内部都默许相关着一个CALayer,咱们能够称这个Layer为Root Layer(根层)
  • 一切的非Root Layer,也便是手动创立的CALayer目标,都存在着隐式动画

当对非Root Layer的部分特色进行修正时,默许会主动发生一些动画作用,而这些特色称为Animatable Properties(可动画特色)。

常见的几个可动画特色:

bounds:用于设置CALayer的宽度和高度。修正这个特色会发生缩放动画
backgroundColor:用于设置CALayer的布景色。修正这个特色会发生布景色的突变动画
position:用于设置CALayer的方位。修正这个特色会发生平移动画
borderColor:边框色彩
opacity:不透明度

能够经过业务封闭隐式动画:

[CATransaction begin];
// 封闭隐式动画
[CATransaction setDisableActions:YES];
self.myview.layer.position = CGPointMake(10, 10);
[CATransaction commit];
  • CATransaction业务类能够对多个layer的特色一起进行修正,它分隐式业务显式业务
  • 当咱们向图层增加显式或隐式动画时,Core Animation都会主动创立隐式业务。
  • 可是,咱们还能够创立显式业务以更精确地办理这些动画。
  • 区别隐式动画和隐式业务:
    隐式动画经过隐式业务完结动画 。
  • 区别显式动画和显式业务:
    显式动画有多种完结办法,显式业务是一种完结显式动画的办法。
  • 除显式业务外,任何关于CALayer特色的修正,都是隐式业务.

隐式业务

//创立layer
let layer = CALayer()
layer.bounds = CGRect(x: 0, y: 0, width: 100, height: 100)
layer.position = CGPoint(x: 100, y: 350)
layer.backgroundColor = UIColor.red.cgColor
layer.borderColor = UIColor.black.cgColor
layer.opacity = 1.0
view.layer.addSublayer(layer)
//触发动画
// 设置改动动画进程是否显现,默许为true不显现
CATransaction.setDisableActions(false)
layer.cornerRadius = (layer.cornerRadius == 0.0) ? 30.0 : 0.0
layer.opacity = (layer.opacity == 1.0) ? 0.5 : 1.0

显式业务:经过明确的调用begin,commit来提交动画

CATransaction.begin()
layer.zPosition = 200.0
layer.opacity = 0.0
CATransaction.commit()

运用业务CATransaction的主要原因:

  • 在显式业务的规模内,咱们能够更改继续时刻,计时功用和其他参数。
  • 还能够为整个业务分配完结块,以便在动画组完结时告知运用。

例如,将动画的默许继续时刻更改为8秒,运用setValue:forKey:办法进行修正,现在支撑的特色包含: "animationDuration", "animationTimingFunction","completionBlock", "disableActions".

CATransaction.begin()
CATransaction.setValue(8.0, forKey: "animationDuration")
//履行动画
CATransaction.commit()

嵌套业务:

  • 当咱们要为不同动画集供给不同默许值的状况下能够运用嵌套业务
  • 要将一个业务嵌套在另一个业务中,只需再次调用begin,且每个begin调用有必要一一对应一个commit办法。
  • 只要在为最外层业务提交更改后,Core Animation才会开端相关的动画。

嵌套显式业务代码

//业务嵌套
CATransaction.begin()   // 外部transaction
CATransaction.setValue(2.0, forKey: "animationDuration")
layer.position = CGPoint(x: 140, y: 140)
CATransaction.begin()   // 内部transaction
CATransaction.setValue(5.0, forKey: "animationDuration")
layer.zPosition = 200.0
layer.opacity = 0.0
CATransaction.commit()  // 内部transaction
CATransaction.commit()  // 外部transaction

5. Core Animation动画简介

  • Core Animation能够用在Mac OS X和iOS平台。
  • Core Animation的动画履行进程都是在后台操作的,不会阻塞主线程。
  • 要留意的是,Core Animation是直接作用在CALayer上的,并非UIView。
  • 乔帮主在2007年的WWDC大会上亲自为你演示Core Animation的强壮:点击检查视频

6. 中心动画开发进程

  1. 运用它需求先增加QuartzCore.framework结构和引入主头文件<QuartzCore/QuartzCore.h> (假如是xcode5之前的版本,运用它需求先增加QuartzCore.framework和引入对应的结构<QuartzCore/QuartzCore.h>)
  2. 初始化一个CAAnimation目标,并设置一些动画相关特色
  3. 经过调用CALayer的addAnimation:forKey:办法增加CAAnimation目标到CALayer中,这样就能开端履行动画了
  4. 经过调用CALayer的removeAnimationForKey:办法能够停止CALayer中的动画

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

7. CAAnimation——一切动画目标的父类

是一切动画目标的父类,担任操控动画的继续时刻和速度,是个抽象类,不能直接运用,应该运用它详细的子类
特色阐明:(带*号代表来自CAMediaTiming协议的特色)

  • *duration:动画的继续时刻
  • *repeatCount:重复次数,无限循环能够设置HUGE_VALF或许MAXFLOAT
  • *repeatDuration:重复时刻
  • removedOnCompletion:默许为YES,代表动画履行完毕后就从图层上移除,图形会康复到动画履行前的状况。假如想让图层坚持显现动画履行后的状况,那就设置为NO,不过还要设置fillMode为kCAFillModeForwards
  • *fillMode:决议当时目标在非active时刻段的行为。比方动画开端之前或许动画完毕之后
  • *beginTime:能够用来设置动画推迟履行时刻,若想推迟2s,就设置为CACurrentMediaTime()+2,CACurrentMediaTime()为图层的当时时刻
  • timingFunction:速度操控函数,操控动画运转的节奏
  • delegate:动画署理

8. CAAnimation——动画填充办法

  • fillMode特色值(要想fillMode有用,最好设置removedOnCompletion = NO)
  • kCAFillModeRemoved 这个是默许值,也便是说当动画开端前和动画完毕后,动画对layer都没有影响,动画完毕后,layer会康复到之前的状况
  • kCAFillModeForwards 当动画完毕后,layer会一直坚持着动画终究的状况
  • kCAFillModeBackwards 在动画开端前,只需求将动画加入了一个layer,layer便当即进入动画的初始状况并等待动画开端。
  • kCAFillModeBoth 这个其实便是上面两个的合成.动画加入后开端之前,layer便处于动画初始状况,动画完毕后layer坚持动画终究的状况

9. CAAnimation——速度操控函数

速度操控函数(CAMediaTimingFunction)

  • kCAMediaTimingFunctionLinear(线性):匀速,给你一个相对静态的感觉
  • kCAMediaTimingFunctionEaseIn(渐进):动画缓慢进入,然后加快脱离
  • kCAMediaTimingFunctionEaseOut(渐出):动画全速进入,然后减速的抵达目的地
  • kCAMediaTimingFunctionEaseInEaseOut(渐进渐出):动画缓慢的进入,中心加快,然后减速的抵达目的地。这个是默许的动画行为。

设置动画的履行节奏
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

10. CAAnimation——动画署理办法

CAAnimation在分类中界说了署理办法,是给NSObject增加的分类,所以任何目标,成为CAAnimation的署理都能够

@interface NSObject (CAAnimationDelegate)
/* Called when the animation begins its active duration. */
动画开端的时分调用
- (void)animationDidStart:(CAAnimation *)anim;
动画停止的时分调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;
@end

11. CALayer上动画的暂停和康复

#pragma mark 暂停CALayer的动画
-(void)pauseLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    //让CALayer的时刻停止走动
    layer.speed = 0.0;
    //让CALayer的时刻停留在pausedTime这个时刻
    layer.timeOffset = pausedTime;
}

12. CALayer上动画的康复

#pragma mark 康复CALayer的动画
-(void)resumeLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = layer.timeOffset;
    // 1. 让CALayer的时刻继续行走
    layer.speed = 1.0;
    // 2. 撤销上次记载的停留时刻
    layer.timeOffset = 0.0;
    // 3. 撤销上次设置的时刻
    layer.beginTime = 0.0;
    // 4. 核算暂停的时刻(这儿也能够用CACurrentMediaTime()-pausedTime)
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    // 5. 设置相关于父坐标系的开端时刻(往后退timeSincePause)
    layer.beginTime = timeSincePause;
}

13. CAPropertyAnimation

是CAAnimation的子类,也是个抽象类,要想创立动画目标,应该运用它的两个子类:

  • CABasicAnimation
  • CAKeyframeAnimation

特色阐明:
keyPath:经过指定CALayer的一个特色名称为keyPath(NSString类型),而且对CALayer的这个特色的值进行修正,到达相应的动画作用。比方,指定@“position”为keyPath,就修正CALayer的position特色的值,以到达平移的动画作用

14. CABasicAnimation——根本动画

根本动画,是CAPropertyAnimation的子类

特色阐明:

  • keyPath:要改动的特色名称(传字符串)
  • fromValue:keyPath相应特色的初始值
  • toValue:keyPath相应特色的完毕值

动画进程阐明:

  • 跟着动画的进行,在长度为duration的继续时刻内,keyPath相应特色的值从fromValue渐渐地变为toValue
  • keyPath内容是CALayer的可动画Animatable特色

假如fillMode=kCAFillModeForwards一起removedOnComletion=NO,那么在动画履行完毕后,图层会坚持显现动画履行后的状况。但在实质上,图层的特色值还是动画履行前的初始值,并没有真正被改动。

    //创立动画
    CABasicAnimation *anim = [CABasicAnimation animation];;
    //    设置动画目标
    // keyPath决议了履行怎样的动画,调用layer的哪个特色来履行动画
    //     position:平移
    anim.keyPath = @"position";
    //    包装成目标
    anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];;
    anim.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
    anim.duration = 2.0;
    //    让图层坚持动画履行完毕后的状况
    //    履行完毕以后不要删去动画
    anim.removedOnCompletion = NO;
    //    坚持最新的状况
    anim.fillMode = kCAFillModeForwards;
    //    增加动画
    [self.layer addAnimation:anim forKey:nil];

举个比方:

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】
代码如下:

//创立动画目标
    CABasicAnimation *anim = [CABasicAnimation animation];
    //设置动画特色
    anim.keyPath = @"position.y";
    anim.toValue = @300;
    //动画提交时,会主动删去动画
    anim.removedOnCompletion = NO;
    //设置动画终究坚持状况
    anim.fillMode = kCAFillModeForwards;
    //增加动画目标
    [self.redView.layer addAnimation:anim forKey:nil];

15. CAKeyframeAnimation——关键帧动画

关键帧动画,也是CAPropertyAnimation的子类,与CABasicAnimation的区别是:

  • CABasicAnimation只能从一个数值(fromValue)变到另一个数值(toValue)
  • 而CAKeyframeAnimation会运用一个NSArray保存这些数值

特色阐明:

  • values: 上述的NSArray目标。里边的元素称为“关键帧”(keyframe)。动画目标会在指定的时刻(duration)内,顺次显现values数组中的每一个关键帧
  • path: 代表途径能够设置一个CGPathRef、CGMutablePathRef,让图层依照途径轨道移动。path只对CALayer的

anchorPoint和position起作用。假如设置了path,那么values将被疏忽

  • keyTimes:能够为对应的关键帧指定对应的时刻点,其取值规模为0到1.0,keyTimes中的每一个时刻值都对应values中的每一帧。假如没有设置keyTimes,各个关键帧的时刻是平分的

CABasicAnimation可看做是只要2个关键帧的CAKeyframeAnimation

//    创立动画
  CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];;
//    设置动画目标
//  keyPath决议了履行怎样的动画,调整哪个特色来履行动画
  anim.keyPath = @"position";
  NSValue *v1 = [NSValue valueWithCGPoint:CGPointMake(100, 0)];
  NSValue *v2 = [NSValue valueWithCGPoint:CGPointMake(200, 0)];
  NSValue *v3 = [NSValue valueWithCGPoint:CGPointMake(300, 0)];
  NSValue *v4 = [NSValue valueWithCGPoint:CGPointMake(400, 0)];
  anim.values = @[v1,v2,v3,v4];
  anim.duration = 2.0;
//    让图层坚持动画履行完毕后的状况
//    状况履行完毕后不要删去动画
  anim.removedOnCompletion = NO;
//    坚持最新的状况
  anim.fillMode = kCAFillModeForwards;
//    增加动画
  [self.layer addAnimation:anim forKey:nil];
//  依据途径创立动画
//    创立动画
  CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];;
  anim.keyPath = @"position";
  anim.removedOnCompletion = NO;
  anim.fillMode = kCAFillModeForwards;
  anim.duration = 2.0;
//    创立一个途径
  CGMutablePathRef path = CGPathCreateMutable();
//    途径的规模
  CGPathAddEllipseInRect(path, NULL, CGRectMake(100, 100, 200, 200));
//    增加途径
  anim.path = path;
//    开释途径(带Create的函数创立的目标都需求手动开释,否则会内存走漏)
  CGPathRelease(path);
//    增加到View的layer
  [self.redView.layer addAnimation:anim forKey];

举个比方:

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

代码如下:

//帧动画
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    anim.keyPath = @"transform.rotation";
    anim.values = @[@(angle2Radio(-5)),@(angle2Radio(5)),@(angle2Radio(-5))];
    anim.repeatCount = MAXFLOAT;
    //主动反转
    //anim.autoreverses = YES;
    [self.imageV.layer addAnimation:anim forKey:nil];

再举个比方:

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

代码如下:


#import "ViewController.h"
@interface ViewController ()
/** 注释*/
@property (nonatomic ,weak) CALayer *fistLayer;
@property (strong, nonatomic)  NSMutableArray *imageArray;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    //设置布景
    self.view.layer.contents = (id)[UIImage imageNamed:@"bg"].CGImage;
    CALayer *fistLayer = [CALayer layer];
    fistLayer.frame = CGRectMake(100, 288, 89, 40);
    //fistLayer.backgroundColor = [UIColor redColor].CGColor;
    [self.view.layer addSublayer:fistLayer];
    self.fistLayer = fistLayer;
    //fistLayer.transform = CATransform3DMakeRotation(M_PI, 0, 0, 1);
    //加载图片
    NSMutableArray *imageArray = [NSMutableArray array];
    for (int i = 0; i < 10; i++) {
       UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"fish%d",i]];
        [imageArray addObject:image];
    }
    self.imageArray = imageArray;
    //增加定时器
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(update) userInfo:nil repeats:YES];
    //增加动画
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    anim.keyPath = @"position";
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(100, 200)];
    [path addLineToPoint:CGPointMake(350, 200)];
    [path addLineToPoint:CGPointMake(350, 500)];
    [path addQuadCurveToPoint:CGPointMake(100, 200) controlPoint:CGPointMake(150, 700)];
    //传入途径
    anim.path = path.CGPath;
    anim.duration  = 5;
    anim.repeatCount = MAXFLOAT;
    anim.calculationMode = @"cubicPaced";
    anim.rotationMode = @"autoReverse";
    [fistLayer addAnimation:anim forKey:nil];
}
static int _imageIndex = 0;
- (void)update {
    //从数组傍边取出图片
    UIImage *image = self.imageArray[_imageIndex];
    self.fistLayer.contents = (id)image.CGImage;
    _imageIndex++;
    if (_imageIndex > 9) {
        _imageIndex = 0;
    }
}
@end

16. 转场动画——CATransition

CATransition是CAAnimation的子类,用于做转场动画,能够为层供给移出屏幕和移入屏幕的动画作用。iOS比Mac OS X的转场动画作用少一点
UINavigationController便是经过CATransition完结了将操控器的视图推入屏幕的动画作用
动画特色:(有的特色是具有方向的,详情看下图)
type:动画过渡类型
subtype:动画过渡方向
startProgress:动画起点(在全体动画的百分比)
endProgress:动画终点(在全体动画的百分比)

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

    CATransition *anim = [CATransition animation];
    转场类型
    anim.type = @"cube";
    动画履行时刻
    anim.duration = 0.5;
    动画履行方向
    anim.subtype = kCATransitionFromLeft;
    增加到View的layer
    [self.redView.layer addAnimation:anim forKey];

举个比方:


#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageV;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.imageV.userInteractionEnabled = YES;
    //增加手势
    UISwipeGestureRecognizer *leftSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
    leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
    [self.imageV addGestureRecognizer:leftSwipe];
    UISwipeGestureRecognizer *rightSwipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
    rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
    [self.imageV addGestureRecognizer:rightSwipe];
}
static int _imageIndex = 0;
- (void)swipe:(UISwipeGestureRecognizer *)swipe {
    //转场代码与转场动画有必要得在同一个办法傍边.
    NSString *dir = nil;
    if (swipe.direction == UISwipeGestureRecognizerDirectionLeft) {
        _imageIndex++;
        if (_imageIndex > 4) {
            _imageIndex = 0;
        }
        NSString *imageName = [NSString stringWithFormat:@"%d",_imageIndex];
        self.imageV.image = [UIImage imageNamed:imageName];
        dir = @"fromRight";
    }else if (swipe.direction == UISwipeGestureRecognizerDirectionRight) {
        _imageIndex--;
        if (_imageIndex < 0) {
            _imageIndex = 4;
        }
        NSString *imageName = [NSString stringWithFormat:@"%d",_imageIndex];
        self.imageV.image = [UIImage imageNamed:imageName];
        dir = @"fromLeft";
    }
    //增加动画
    CATransition *anim = [CATransition animation];
    //设置转场类型
    anim.type = @"cube";
    //设置转场的方向
    anim.subtype = dir;
    anim.duration = 0.5;
    //动画从哪个点开端
    //    anim.startProgress = 0.2;
    //    anim.endProgress = 0.3;
    [self.imageV.layer addAnimation:anim forKey:nil];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

17. CAAnimationGroup——动画组

动画组,是CAAnimation的子类,能够保存一组动画目标,将CAAnimationGroup目标加入层后,组中一切动画目标能够一起并发运转

特色阐明:
animations:用来保存一组动画目标的NSArray
默许状况下,一组动画目标是一起运转的,也能够经过设置动画目标的beginTime特色来更改动画的开端时刻

    CAAnimationGroup *group = [CAAnimationGroup animation];
//    创立旋转动画目标
    CABasicAnimation *retate = [CABasicAnimation animation];
//    layer的旋转特色
    retate.keyPath = @"transform.rotation";
//    视点
    retate.toValue = @(M_PI);
//    创立缩放动画目标
    CABasicAnimation *scale = [CABasicAnimation animation];
//    缩放特色
    scale.keyPath = @"transform.scale";
//    缩放份额
    scale.toValue = @(0.0);
//    增加到动画组傍边
    group.animations = @[retate,scale];
//           履行动画时刻
    group.duration = 2.0;
//    履行完以后不要删去动画
    group.removedOnCompletion = NO;
//          坚持最新的状况
    group.fillMode = kCAFillModeForwards;
    [self.view.layer addAnimation:group forKey:nil];

举个:

CAAnimationGroup.gif

代码如下:

#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIView *redView;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //移动
    CABasicAnimation *anim = [CABasicAnimation animation];
    anim.keyPath =  @"position.y";
    anim.toValue = @500;
//    anim.removedOnCompletion = NO;
//    anim.fillMode = kCAFillModeForwards;
//    [self.redView.layer addAnimation:anim forKey:nil];
//    
    //缩放
    CABasicAnimation *anim2 = [CABasicAnimation animation];
    anim2.keyPath =  @"transform.scale";
    anim2.toValue = @0.5;
//    anim2.removedOnCompletion = NO;
//    anim2.fillMode = kCAFillModeForwards;
//    [self.redView.layer addAnimation:anim2 forKey:nil];
    CAAnimationGroup *groupAnim = [CAAnimationGroup animation];
    //会履行数组傍边每一个动画目标
    groupAnim.animations = @[anim,anim2];
    groupAnim.removedOnCompletion = NO;
    groupAnim.fillMode = kCAFillModeForwards;
    [self.redView.layer addAnimation:groupAnim forKey:nil];
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

三大动画:(不需求交互的时分能够选择以下动画)
CAAnimationGroup——动画组
CAKeyframeAnimation——关键帧动画
转场动画——CATransition

//参数阐明:
 duration:动画的继续时刻
 view:需求进行转场动画的视图
 options:转场动画的类型
 animations:将改动视图特色的代码放在这个block中
 completion:动画完毕后,会主动调用这个block
 + (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;

运用UIView动画函数完结转场动画——双视图

参数阐明:
duration:动画的继续时刻
options:转场动画的类型
animations:将改动视图特色的代码放在这个block中
completion:动画完毕后,会主动调用这个block
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion;

转场动画
1.创立转场动画:[CATransition animation];
2.设置动画特色值
3.增加到需求专场动画的图层上 [layer addAimation:animation forKer:nil];

转场动画的类型(NSString *type)
fade : 穿插淡化过渡
push : 新视图把旧视图推出去
moveIn: 新视图移到旧视图上面
reveal: 将旧视图移开,显现下面的新视图
cube : 立方体翻滚作用
oglFlip : 上下左右翻转作用
suckEffect : 缩短作用,如一块布被抽走
rippleEffect: 水滴作用
pageCurl : 向上翻页作用
pageUnCurl : 向下翻页作用
cameraIrisHollowOpen : 相机镜头打开作用
cameraIrisHollowClos : 相机镜头封闭作用

留意:

  • 中心动画仅仅修正了控件的图形树,换句话说便是仅仅修正了他的显现,并没有改动控件的真实方位!!!
  • 也便是说在动画的进程中点击控件是不能跟用户进行交互的,牢记牢记!!!
  • 当然,点击控件的开端方位是能够的。

四、粒子动画

  • CAEmitterLayer 是一个高性能的粒子引擎,被用来创立 实时粒子动画如: 烟雾火花等等这些作用
  • CAEmitterLayer 常与 CAEmitterCell 结合运用
    • 你将会为不同的比方作用界说一个或多个CAEmitterCell作为模版,
    • 一起CAEmitterLayer担任依据这些模版实例化一个粒子流。
    • 一个CAEmitterCell类似于一个CALayer:
      它有一个contents特色能够界说为一个CGImage,别的还有一些可设置特色操控着体现和行为。

1. CAEmitterLayer

1.1 CAEmitterLayer常用特色

@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 用来装粒子的数组
@property float birthRate; // 粒子发生系数,默许1.0
@property float lifetime; // 粒子的生命周期系数, 默许1.0
@property CGPoint emitterPosition; // 决议了粒子发射形状的中心点
@property CGFloat emitterZPosition;
@property CGSize emitterSize; // 发射源的尺寸巨细
@property CGFloat emitterDepth;
@property(copy) NSString *emitterShape; // 发射源的形状
@property(copy) NSString *emitterMode; // 发射办法
@property(copy) NSString *renderMode; // 烘托办法
@property BOOL preservesDepth;
@property float velocity; // 粒子速度系数, 默许1.0
@property float scale; // 粒子的缩放份额系数, 默许1.0
@property float spin; // 粒子的自旋转速度系数, 默许1.0
@property unsigned int seed; // 随机数发生器

CAEmitterLayer里边的API里边的一切特色都现已贴出来并作了阐明,看看注释并调试一下就能了解大部分,接下来关键说说一些常用的特色

  • renderMode:烘托办法,操控着在视觉上粒子图片是怎么混合的。
    NSString * const kCAEmitterLayerUnordered;
    NSString * const kCAEmitterLayerOldestFirst;
    NSString * const kCAEmitterLayerOldestLast;
    NSString * const kCAEmitterLayerBackToFront;
    NSString * const kCAEmitterLayerAdditive;
    
  • emitterMode: 发射办法,这个字段规则了在特定形状上发射的详细办法是什么
    kCAEmitterLayerPoints: 点办法,发射器是以点的局势发射粒子。
    kCAEmitterLayerOutline:这个办法下整个边框都是发射点,即边框进行发射
    kCAEmitterLayerSurface:这个办法下是咱们边框包含下的区域进行抛洒
    kCAEmitterLayerVolume: 同上
    
  • emitterShape:规则了发射源的形状。
    kCAEmitterLayerPoint:点形状,发射源的形状便是一个点,方位在上面position设置的方位
    kCAEmitterLayerLine:线形状,发射源的形状是一条线,方位在rect的横向的坐落笔直方向中心那条
    kCAEmitterLayerRectangle:矩形状,发射源是一个矩形,便是上面生成的那个矩形rect
    kCAEmitterLayerCuboid:立体矩形形状,发射源是一个立体矩形,这儿要生效的话需求设置z方向的数据,假如不设置就同矩形状
    kCAEmitterLayerCircle:圆形形状,发射源是一个圆形,形状为矩形包裹的那个圆,二维的
    kCAEmitterLayerSphere:立体圆形,三维的圆形,同样需求设置z方向数据,不设置则通二维相同
    
  • emitterSize:发射源的巨细,这个emitterSize结合position构建了发射源的方位及巨细的矩形区域rect
  • emitterPosition:发射点的方位。
  • lifetime:粒子的生命周期。
  • velocity:粒子速度。
  • scale:粒子缩放份额。
  • spin:自旋转速度。
  • seed:用于初始化发生的随机数发生的种子。
  • emitterCells:CAEmitterCell目标的数组,被用于把粒子投放到layer上

1.2 CAEmitterLayer决议粒子系数的特色

  • birthRate: 粒子发生系数,默许1.0;每个粒子cell的发生率乘以这个粒子发生系数,得出每一秒发生这个粒子的个数。 即:每秒粒子发生个数 = layer.birthRate * cell.birthRate ;
  • lifetime:粒子的生命周期系数,默许1.0。核算办法同上;
  • velocity:粒子速度系数, 默许1.0。核算办法同上;
  • scale:粒子的缩放份额系数, 默许1.0。核算办法同上;
  • spin:自旋转速度系数, 默许1.0。核算办法同上;

1.3 CAEmitterLayer决议粒子内容的特色

  • emitterCells:用来装粒子的数组。每种粒子便是一个CAEmitterCell。在API中能够看到CAEmitterCell是服从CAMediatiming协议的,能够经过beginTime来操控subCell的出现机遇

2. CAEmitterCell

2.1 CAEmitterCell常用特色

@property(nullable, copy) NSString *name; // 粒子姓名, 默许为nil
@property(getter=isEnabled) BOOL enabled; 
@property float birthRate; // 粒子的发生率,默许0
@property float lifetime; // 粒子的生命周期,以秒为单位。默许0
@property float lifetimeRange; // 粒子的生命周期的规模,以秒为单位。默许0
@property CGFloat emissionLatitude;// 指定纬度,纬度角代表了在x-z轴平面坐标系中与x轴之间的夹角,默许0: 
@property CGFloat emissionLongitude; // 指定经度,经度角代表了在x-y轴平面坐标系中与x轴之间的夹角,默许0:
@property CGFloat emissionRange; //发射视点规模,默许0,以锥形散布开的发射视点。视点用弧度制。粒子均匀散布在这个锥形规模内;
@property CGFloat velocity; // 速度和速度规模,两者默许0
@property CGFloat velocityRange;
@property CGFloat xAcceleration; // x,y,z方向上的加快度重量,三者默许都是0
@property CGFloat yAcceleration;
@property CGFloat zAcceleration;
@property CGFloat scale; // 缩放份额, 默许是1
@property CGFloat scaleRange; // 缩放份额规模,默许是0
@property CGFloat scaleSpeed; // 在生命周期内的缩放速度,默许是0
@property CGFloat spin; // 粒子的均匀旋转速度,默许是0
@property CGFloat spinRange; // 自旋转视点规模,弧度制,默许是0
@property(nullable) CGColorRef color; // 粒子的色彩,默许白色
@property float redRange; // 粒子色彩red,green,blue,alpha能改动的规模,默许0
@property float greenRange;
@property float blueRange;
@property float alphaRange;
@property float redSpeed; // 粒子色彩red,green,blue,alpha在生命周期内的改动速度,默许都是0
@property float greenSpeed;
@property float blueSpeed;
@property float alphaSpeed;
@property(nullable, strong) id contents; // 粒子的内容,为CGImageRef的目标
@property CGRect contentsRect;
@property CGFloat contentsScale;
@property(copy) NSString *minificationFilter;
@property(copy) NSString *magnificationFilter;
@property float minificationFilterBias;
@property(nullable, copy) NSArray<CAEmitterCell *> *emitterCells; // 粒子里边的粒子
@property(nullable, copy) NSDictionary *style;

CAEmitterCell里边的API里边的大部分特色作了阐明,看看注释并调试一下就能了解大部分,接下来关键说说一些常用的特色。CAEmitterLayer便是粒子的工厂,可是要完结作用就需求CAEmitterCell的帮助。

  • 粒子在X.Y.Z三个方向上的加快度。
    @property CGFloat xAcceleration;
    @property CGFloat yAcceleration;
    @property CGFloat zAcceleration;
    
  • 粒子缩放份额、缩放规模及缩放速度。(0.0`1.0)
    @property CGFloat scale;
    @property CGFloat scaleRange;
    @property CGFloat scaleSpeed;
    
  • 粒子自旋转速度及规模:
    @property CGFloat spin;
    @property CGFloat spinRange;
    
  • 粒子RGB及alpha改动规模、速度。
    //规模:
    @property float redRange;
    @property float greenRange;
    @property float blueRange;
    @property float alphaRange;
    //速度:
    @property float redSpeed;
    @property float greenSpeed;
    @property float blueSpeed;
    @property float alphaSpeed;
    
  • emitterCells:子粒子。
  • color:指定了一个能够混合图片内容色彩的混合色。
  • birthRate:粒子发生系数,默许1.0.
  • contents:是个CGImageRef的目标,即粒子要展示的图片;
  • emissionRange:值是2(代码写成M_PI * 2.0f),这意味着粒子能够从360度恣意方位反射出来。假如指定一个小一些的值,就能够创造出一个圆锥形。
  • 指定值在时刻线上的改动,例如:alphaSpeed = 0.4,阐明粒子每过一秒减小0.4。

2.2 CAEmitterCell决议生命状况的特色

  • lifetimelifetimeRange:粒子在体系上的生命周期,即存活时刻,单位是秒。配合lifetimeRage来让粒子生命周期均匀改动,以便能够让粒子的出现和消失显得更加离散。
  • birthRate:每秒钟发生的粒子的数量,是浮点数。关于这个数量为浮点数,在测验的时分能够灵敏运用它。比方你想看粒子的运动状况,可是太多了可能会很模糊,这时分你把birthRate = 0.1f,其他参数不变,就能看到单个粒子的运动状况。

2.3 CAEmitterCell决议内容的特色

  • contents:为CGImageRef的目标。关于contents会联想到CALayer了,在CALayer中展示静态的图片是需求用到这个特色。供给一张图片,作为粒子体系的粒子。可是由于粒子体系能够给粒子上色,为了做出好的色彩变换作用,一般供给的图片为纯色的图片,一般为白色。
  • name:粒子的姓名。初看没什么用,可是当CAEmitterLayer里边有很多个cell的时分,给每个cell设置好姓名,要修正一些特色以到达动画作用的改动等,就能够经过KVC拿到这个cell的某个特色。在后边的几个demo中都用用到。

2.4 CAEmitterCell决议色彩状况的特色

粒子体系之所以能做出炫酷的作用,和它的色彩多样化有必不可上的联系,在CAEmitterCell中供给了较多的色彩操控特色这部分特色让你获得了操控粒子色彩,色彩改动规模和速度的才能,你能够凭借它来完结一些突变的作用或其它构建在它之上的酷炫作用。接下来就看看这些色彩特色。

  • colorcolor是粒子的色彩特色,这个色彩特色的作用是给粒子上色,它的完结办法很简单,便是将contents本身的色彩的RGBA值 * color的RGBA值,就得到终究的粒子的色彩。为了很好的核算,一般用白色的图片作为contents,由于它的RGB都是255,转化为UIColor中的component便是1,用color乘上它就能得到color设置的色彩作用。
  • redRangegreenRangeblueRangealphaRange:这些是对应的color的RGBA的取值规模,取值规模为0~1,比方如下设置中
snowCell.color = [[UIColor colorWithRed:0.1 green:0.2 blue:0.3 alpha:0.5]CGColor];
snowCell.redRange = 0.1;
snowCell.greenRange = 0.1;
snowCell.blueRange = 0.1;
snowCell.alphaRange = 0.1;

对应的RGBA的取值规模便是:R(00.2)、G(0.10.3)、B(0.20.4)、A(0.40.6)。

  • redSpeedgreenSpeedblueSpeedalphaSpeed:这些是对应的是粒子的RGBA的改动速度,取值规模为0~1。表明每秒钟的RGBA的改动率。这个改动率的核算办法其实很简单,先看下面的几行代码:
snowCell.lifetime = 20.f;  // 粒子的生命周期
snowCell.color = [[UIColor colorWithRed:0.f green:1.f blue:1.f alpha:1.f]CGColor];
snowCell.redSpeed = 0.2;

这儿设置了粒子色彩的RGBA,以及redSpeed,其他的没设置默许为0。粒子的生命周期(lifetime)为20秒,那么这个粒子从发生到消失的时刻便是20秒。它的Red值为0,redSpeed为0.2,那么在粒子的这个生命周期内,粒子的每秒钟的Rde值就会增加0.2 * 255,体现在外观上的状况便是粒子色彩在不断改动,挨近白色。终究粒子生命周期完毕的时分,粒子的color正好是RGBA(1,1,1,1)。当然个改动的速度也能够负数,核算办法相同。比方要设置焰火的作用,那么要让在爆炸的进程中色彩改动,便是经过这样的设置到达的作用。

2.5 CAEmitterCell决议飞翔轨道的特色。

CAEmitterLayer尽管操控了粒子的发射方位和形状等,可是粒子的飞翔一起也需求本身去决议,比方粒子发射的视点、发散的规模,自转特色等。那么接下来就说说这些特色。

  • emissionLongitude: 指定经度,经度角代表了在x-y轴平面坐标系中与x轴之间的夹角,默许0,弧度制。顺时针方向为正。这样解释看起来不好懂,画个图就了解了。

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

粒子沿着X轴向右飞翔,假如`emissionLongtitude = 0`那么粒子会沿着X轴向右飞翔,假如想沿着Y轴向下飞翔,那么能够设置`emissionLongtitude = M_PI_2`
  • emissionLatitude:这个和emissionLongitude的原理是相同的,只不过是在三维平面上的x-z轴上与x轴的夹角。

  • emissionRange:发射视点规模,默许0,以锥形散布开的发射视点。视点用弧度制。粒子均匀散布在这个锥形规模内。在二维平面中,若想要以锥形的办法发射粒子,然粒子的发散规模不是一条线,而是一个锥形区域(也能够叫做扇形),那么能够经过emissionRange来设置一个规模。比方想沿Y轴向下成90度的锥形区域发散,那么能够经过如下代码设置:

snowCell.emissionLongitude = M_PI_2;
snowCell.emissionRange = M_PI_4;

完结的作用如下:

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

能够看到粒子是沿着Y轴向下成90度的一个发散视点。假如想完结火焰等作用。就能够这样,把视点调小一点即可。

  • velocityvelocityRangexAccelerationyAccelerationzAcceleration:前面两个是粒子的初速度和初速度的规模,后边是三个分别是在x、y、z轴方向的加快度,这个很好了解,初中就应该知道加快度的概念,也便是每秒钟速度的改动量。在放焰火的作用中,焰火飞上天的进程中,模仿一个收重力影响的作用,就能够经过yAcceleration模仿一个重力加快度的作用。
  • spinspinRange:这两个特色很重要,是粒子的自转特色。在粒子被发射出去之后,想要完结自转,就需求用到他们。**粒子的自转是以弧度制来核算的,表明每秒钟粒子自转的弧度数。spin为正数代表粒子是顺时针旋转的,为负数的话便是逆时针选转了。**举个:粒子的生命周期便是20秒,那么你想让你的粒子这个生命周期内刚好自转12周,若spinRange为0,那么粒子的spin值就应该为((PI/180)*360 * 12)/20,就得到了每秒需求转动的弧度数。

2.6 CAEmitterCell子粒子的特色

  • emitterCells:看到CAEmitterCell的这个特色的时分或许会有些疑问,不用惊奇,前面说过CAEmitterLayer能够发生cell,通用cell也能够发生cell。那么这个特色就和CAEmitterLayer中的emitterCells相同,也是一个数组。这儿有几个需求留意的当地:

    1. 若给cell设置了subCell,若想操控subCell的方向,那么得考虑父cell的方向特色,也便是emissionLongtitudeemissionLatitude这两个特色的状况。

    2. 不管父粒子cell是从什么样的形状上发射出来的,若要发射subCell,subCell总是从kCAEmitterLayerPoint形状上由父粒子的中心发射出来的。

3. 留意

  • CAEmitterLayerCAEmitterCell 中 有相同的特色,他们操控相同的特性
  • 若是相同特色都各自设置了值,粒子发射引擎在工作的时分,会把两个值相乘。作为这个特色的终究值来操控显现作用
  • 相同特色如下:
    @property float birthRate; // 每秒发生的粒子数量
    @property float lifetime; // 粒子的生命周期.单位是秒
    @property CGFloat scale; // 粒子的缩放份额
    

代码示例:

    UIView * containView = [[UIView alloc]initWithFrame:self.view.bounds];
    containView.center = self.view.center;
    containView.backgroundColor = self.view.backgroundColor;
    self.containView = containView;
    [self.view addSubview:self.containView];
    CAEmitterLayer *emitter = [CAEmitterLayer layer];
    emitter.frame = self.containView.bounds;
    [self.containView.layer addSublayer:emitter];
    emitter.renderMode = kCAEmitterLayerAdditive;//这会让重叠的当地变得更亮一些。
    emitter.emitterPosition = CGPointMake(emitter.frame.size.width / 2.0, emitter.frame.size.height / 2.0);
    CAEmitterCell *cell = [[CAEmitterCell alloc] init];
    cell.contents = (__bridge id)[UIImage imageNamed:@"star_yellow"].CGImage;
    cell.birthRate = 150;
    cell.lifetime = 5.0;
    cell.color = [UIColor colorWithRed:1 green:0.5 blue:0.1 alpha:1.0].CGColor;
    cell.alphaSpeed = -0.4;
    cell.velocity = 50;
    cell.velocityRange = 50;
    cell.emissionRange = M_PI * 2.0;
    emitter.emitterCells = @[cell];

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

事例2:瀑布飘洒作用

- (void)setupSubviews {
    self.layer.backgroundColor = [UIColor blackColor].CGColor;
    // 装备emitter
    [self emiterLayer].renderMode = kCAEmitterLayerAdditive; // 粒子怎么混合, 这儿是直接重叠
    [self emiterLayer].emitterPosition = CGPointMake(self.frame.size.width, 0); // 发射点的方位
    [self emiterLayer].emitterShape = kCAEmitterLayerPoint;
    NSMutableArray * mArr = @[].mutableCopy;
    int cellCount = 6;
    for (int i = 0; i<cellCount; i++) {
        CAEmitterCell * cell = [self getEmitterCellAction];
        [mArr addObject:cell];
    }
    [self emiterLayer].emitterCells = mArr; // 将粒子组成的数组赋值给CAEmitterLayer的emitterCells特色即可.
}
- (CAEmitterCell *)getEmitterCellAction {
    CAEmitterCell *cell = [[CAEmitterCell alloc] init];
    //    cell.contents = (__bridge id)[UIImage imageNamed:@"coin"].CGImage; // 粒子中的图片
    cell.contents = (__bridge id _Nullable)([self setRandomColorCircleImageSize:CGSizeMake(20, 20)].CGImage);
    cell.yAcceleration = arc4random_uniform(80);   // 粒子的初始加快度
    cell.xAcceleration = -cell.yAcceleration-10;
    cell.birthRate = 10.f;           // 每秒生成粒子的个数
    cell.lifetime = 6.f;            // 粒子存活时刻
    cell.alphaSpeed = -0.1f;        // 粒子消逝的速度
    cell.velocity = 30.f;           // 粒子运动的速度均值
    cell.velocityRange = 100.f;      // 粒子运动的速度扰动规模
    cell.emissionRange = M_PI; // 粒子发射视点, 这儿是一个扇形.
//    cell.scale = 0.2;
//    cell.scaleRange = 0.1;
//    cell.scaleSpeed = 0.02;
    CGFloat colorChangeValue  = 50.0f;
    cell.blueRange = colorChangeValue;
    cell.redRange =  colorChangeValue;
    cell.greenRange =  colorChangeValue;
    return cell;
}

emitterShape发射源形状取值不一起会有不同作用。

  • kCAEmitterLayerPoint:
    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】
  • kCAEmitterLayerLine: 线
    05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

五、UIImageView帧动画

1.相关的特色和办法:

//动画继续时刻
@property (nonatomic) NSTimeInterval animationDuration;         // for one cycle of images. default is number of images * 1/30th of a second (i.e. 30 fps)
//动画继续次数.默许是0,代表无限循环
@property (nonatomic) NSInteger      animationRepeatCount;      // 0 means infinite (default is 0)
//开端动画
- (void)startAnimating;
//完毕动画
- (void)stopAnimating;

2.gif动画/图片数组Demo

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    NSArray *imageArray = [self getImageArrayWithGIFName:@"aisi"];
    self.imageView.animationImages = imageArray;
    self.imageView.animationDuration = 3;
    self.imageView.animationRepeatCount = MAXFLOAT;
    [self.imageView startAnimating];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [_imageView stopAnimating];
    });
}
- (NSArray<UIImage *> *)getImageArrayWithGIFName:(NSString *)imageName {
    NSMutableArray *imageArray = [NSMutableArray array];
    NSString *path = [[NSBundle mainBundle] pathForResource:imageName ofType:@"gif"];
    NSData *data = [NSData dataWithContentsOfFile:path];
    if (!data) {
        NSLog(@"图片不存在!");
        return nil;
    }
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    size_t count = CGImageSourceGetCount(source);
    if (count <= 1) {
        [imageArray addObject:[[UIImage alloc] initWithData:data]];
    }else {
        for (size_t i = 0; i < count; i++) {
            CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
            [imageArray addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
            CGImageRelease(image);
        }
    }
    CFRelease(source);
    return imageArray;
}

05-iOS 多媒体技能| Core Animation关键回忆2【UIKit动画、Core Animation动画、粒子动画、经典第三方动画库等】

六、经典第三方动画库

  • Lottie
    • 描绘: Lottie 是由 Airbnb 开发的一个用于完结高品质动画的库,支撑将 Adobe After Effects 制作的动画导出为 JSON 文件,并在 iOS 上进行播映。
    • 特色: 能够轻松完结复杂的矢量动画作用,如途径动画、形状变换等。
    • GitHub 地址: Lottie
  • Spruce iOS
    • 描绘: Spruce iOS 是一个用于完结列表项动画的库,能够为 UITableView 和 UICollectionView 增加各种炫酷的列表项过渡作用。
    • 特色: 供给了多种内置的过渡作用,如平行、扩大、淡入淡出等,也支撑自界说过渡作用。
    • GitHub 地址: Spruce iOS
  • ViewAnimator
    • 描绘: ViewAnimator 是一个用于完结视图动画的库,支撑为任何视图增加多种动画作用。
    • 特色: 供给了简单易用的 API,支撑多种动画作用,如突变、旋转、弹簧等。
    • GitHub 地址: ViewAnimator
    • 转存失败,建议直接上传图片文件
  • ……

七、自界说转场动画

1. 中心关键

  • 切换页面转场的几种办法:
    • 经过 UIViewController Modal出一个新VC的页面
    • 经过容器操控器 切换 页面
      • 经过 UINavigationController进行PushPop操作,作VC间的页面切换
      • 经过 UITabBarControllerselectIndex 从头赋值,,进行选中VC的切换
  • 转场办法:
    • 默许转场动画: 体系的 ModalPushPopselectVC切换
    • 自界说转场动画:
      • 交互性(完结动画的实例+手势交互)
      • 非交互形(完结动画的实例)
  • 留意:
    • 体系默许转场动画,是体系供给了默许完结动画实例
    • 因而,咱们要自界说转场动画,也要
      • 供给自界说的完结动画实例
      • 在页面转场的机遇,将 自界说的完结动画实例 提交 给体系API
        • 体系 经过 Delegate回调办法 把 页面切换的机遇告知咱们

因而,接下来咱们就要 关键介绍 转场动画 相关的 几个协议(OC、Swift版本的API根本相同.这儿用OCAPI介绍)

2. 完结自界说动画目标|UIViewControllerAnimatedTransitioning

完结自界说动画进程:

    1. 自界说动画目标:
      自界说Class,恪守UIViewControllerAnimatedTransitioning协议
    1. 完结协议中的中心API:
    • 动画履行时刻:
      - transitionDuration:transitionContext
    • 动画详细完结
      - animateTransition:
    • 动画履行完毕的回调
      - animationEnded:
    1. 在页面转场的机遇回调办法中,回来给体系该自界说Class的实例,告知体系动画完结的细节
  • 协议中的API介绍如下:
@protocol UIViewControllerAnimatedTransitioning <NSObject>
// 设置 转场动画的继续时刻
- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;
/*
 * @ param id <UIViewControllerContextTransitioning> 转场动画的上下文目标
 *    担任 供给 页面切换的上下文,也便是前后两个VC的View等信息
 *    自界说动画的本质,便是编写自界说动画代码,在这个回调中,对前后切换页面的View或layer 增加自界说的动画进行切换
 */
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
@optional
// 动画完毕的 回调
- (void)animationEnded:(BOOL) transitionCompleted;
@end

3. 页面转场上下文目标|UIViewControllerContextTransitioning

  • 协议界说了 在履行自界说转场动画时所需的一些办法特色
  • 恪守 该协议,并完结了协议中API的 实例目标由体系的回调办法供给
  • 该实例用于供给有关视图操控器之间转场动画的上下文信息(常用特色和办法介绍):
@protocol UIViewControllerContextTransitioning <NSObject>
// 容器视图,用于包容转场进程中的View
@property(nonatomic, readonly) UIView *containerView;
...
@property(nonatomic, readonly) BOOL transitionWasCancelled;
...
// 用户符号转场动画是否完结,有必要在动画履行完结之后 调用。入参用context实例的transitionWasCancelled特色值的相反值
- (void)completeTransition:(BOOL)didComplete;
// 经过该办法 获取 上下文 切换 的两个FromVC、ToVC
- (nullable __kindof UIViewController *)viewControllerForKey:(UITransitionContextViewControllerKey)key;
// 经过该办法 获取 上下文 切换 的两个FromView、ToView
- (nullable __kindof UIView *)viewForKey:(UITransitionContextViewKey)key API_AVAILABLE(ios(8.0));
...
// 经过该办法 获取 VC 的 终究frame,能够间接获得view的center,size。进行缩放,位移等动画
- (CGRect)finalFrameForViewController:(UIViewController *)vc;
@end

实战示例代码片段:

// This method can only be a no-op if the transition is interactive and not a percentDriven interactive transition.
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    self.transitionContext = transitionContext;
    self.containerView = [transitionContext containerView];
    self.fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    self.toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    // iOS8之后才有
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        self.fromView = [transitionContext viewForKey:UITransitionContextFromViewKey];
        self.toView = [transitionContext viewForKey:UITransitionContextToViewKey];
    } else {
        self.fromView = self.fromViewController.view;
        self.toView = self.toViewController.view;
    }
    ...
    self.toView.frame = [self.transitionContext finalFrameForViewController:self.toViewController];
    // 在动画 履行完结的当地要 有必要履行的代码:
    BOOL wasCancelled = [self.transitionContext transitionWasCancelled];
    [self.transitionContext completeTransition:!wasCancelled];
    ...
}

4. 自界说Modal转场动画|UIViewControllerTransitioningDelegate

这个协议规则了VC1Modal推出 VC2 和 从VC2 dismiss回来 VC1 的两套接口

  • 交互型
    • Modal推出: - animationControllerForPresentedController: presentingController: sourceController:
    • dismiss回来: - animationControllerForDismissedController:
  • 非交互型(一般增加pan手势进行交互)
    • Modal推出: - interactionControllerForPresentation:
    • dismiss回来: - interactionControllerForDismissal:

@protocol UIViewControllerTransitioningDelegate <NSObject>
@optional
// 非交互型: 咱们直接把咱们完结的 自界说动画实例,回来即可「present动画和dismiss动画可相同,也可不同」
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source;
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed;
// 交互型: 咱们要在此供给 完结了 协议`UIViewControllerInteractiveTransitioning`的实例,用于告知体系,动画的履行进展(这依靠咱们 编写的 交互代码,若是用手势交互,则是拖拽的x和参考系x值的百分比...)
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id <UIViewControllerAnimatedTransitioning>)animator;
- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
...
@end

5. 增加交互逻辑|UIViewControllerInteractiveTransitioning

经过 运用 恪守 该协议的 目标,能够获取 开端交互的机遇 和 VC页面切换的 上下文目标,进而增加 交互 逻辑,经常用pan手势增加交互逻辑。编写交互逻辑关键如下:

    1. 在回调办法中,获取 开端交互的机遇
    1. 给vc的view增加交互逻辑
    1. 依据交互逻辑 核算出 转场 动画 的 百分比,把百分比值percent 提交给 VC页面切换的 上下文目标。以到达,经过交互操控转场动画的作用
    1. 这仍然依靠咱们完结的自界说转场动画
    1. 咱们能够用 承继体系的UIPercentDrivenInteractiveTransition类,专心于编写交互逻辑。并在适宜的机遇告知体系 动画履行的 状况(百分比进展、撤销、完毕)
    • - (void)updateInteractiveTransition:(CGFloat)percentComplete;
    • - (void)cancelInteractiveTransition;
    • - (void)finishInteractiveTransition;
@protocol UIViewControllerInteractiveTransitioning <NSObject>
- (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
...
@end

3. UIPercentDrivenInteractiveTransition

@interface UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>
@property (readonly) CGFloat duration;
....
// 这三个API底层都是调用 UIViewControllerContextTransitioning 上下文目标中的相同API
- (void)updateInteractiveTransition:(CGFloat)percentComplete;
- (void)cancelInteractiveTransition;
- (void)finishInteractiveTransition;
@end

6. UINavigationController|自界说转场动画

留意区别:

  • VC1 经过UINavigationController push 推出 VC2; 或许 VC2 pop 回来 VC1 ,是在恪守并了协议 UINavigationControllerDelegate的转场动画办法中进行完结
  • 而不是 恪守了 UIViewControllerTransitioningDelegate 协议 的相关办法;
  • 关于 转场 动画的详细完结交互逻辑的详细完结, 是能够共同的。
  • 相关中心API如下:
@protocol UINavigationControllerDelegate <NSObject>
...
// 自界说交互逻辑完结接口
- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                          interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController API_AVAILABLE(ios(7.0));
// 自界说转场动画接口
- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                   animationControllerForOperation:(UINavigationControllerOperation)operation
                                                fromViewController:(UIViewController *)fromVC
                                                  toViewController:(UIViewController *)toVC  API_AVAILABLE(ios(7.0));
@end

7. UITabBarController|自界说转场动画

留意区别:

  • UITabBarController select 一个新的 index 进行 页面切换,是在恪守并了协议 UITabBarControllerDelegate的转场动画办法中进行完结
  • 而不是 恪守了 UIViewControllerTransitioningDelegate 协议 的相关办法;
  • 关于 转场 动画的详细完结交互逻辑的详细完结, 是能够共同的。
  • 相关中心API如下:
@protocol UITabBarControllerDelegate <NSObject>
...
// 自界说交互逻辑完结接口
- (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController
                      interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(visionos);
// 自界说转场动画接口
- (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController
            animationControllerForTransitionFromViewController:(UIViewController *)fromVC
                                              toViewController:(UIViewController *)toVC  API_AVAILABLE(ios(7.0)) API_UNAVAILABLE(visionos);
@end

八、动画实战Demo

1. 自界说转场动画Demo

动画的详细完结主要用到UIView的Block动画、CATransition动画; github.com/VanZhang-CN…

2. 粒子动画Demo+CoreAnimation动画+几个layer的实战代码

github.com/VanZhang-CN…