小说《Clione的灯光》改编TV动画,2017年7月开播!动画主题曲由aki担任演唱,此外还有一张宣传图公开。其他消息暂未公布。

在开始学习Core
Animation提供的layer的隐式动画和layer的显式动画之前,我们先来总结一下UIView
block动画
,因为:

前记

关于实现一个iOS动画,如果简单的,我们可以直接调用UIView的代码块来实现,虽然使用UIView封装的方法很方便,但是这只能用于一些简答的动画,如果是一些复杂的动画呢?这就不得不去研究下核心动画Core Animation(包含在Quartz Core框架中)了。这这之前我们必须了解,CALayer就包含在Quartz Core框架中,这是一个跨平台的框架,既可以用在iOS中又可以用在Mac
OS
X中。在使用Core Animation开发动画的本质就是将CALayer中的内容转化为位图从而供硬件操作,所以要熟练掌握动画操作必须熟悉CALayer,关于CALayer就不在这里讲了。今天主要是分析核心动画,iOS
中的核心动画又分为下面几种:基础动画、关键帧动画、动画组、转场动画、弹簧动画。下面我们先来了解下各个动画之间的关系

威尼斯人官网 1core_animation.jpeg

  • 在实际开发中我们用的最多的还是view,而不是layer,所以更多情况下如果我们要做动画的话,用的还是UIView
    block动画,而不是layer的隐式动画和显示动画;
  • 这里总结一下,可以方便我们在后面两篇学习layer的隐式动画和显式动画时作对比,以期加深对动画的理解。
动画简介

CAAnimation
@interface CAAnimation : NSObject <NSCoding, NSCopying, CAMediaTiming, CAAction>{@private void *_attr; uint32_t _flags;}

这是核心动画的基类,不能直接使用,主要负责动画的时间、速度等,从上面可以看出是准守CAMediaTiming协议的。

目录

CAPropertyAnimation

属性动画的基础类,继承自CAAnimation,不能直接使用。何谓属性动画呢?即通过修改属性值就可以产生动画效果。

一、UIView可动画属性列表

CAAnimationGroup

动画组,继承自CAAnimation,顾名思义就是一种组合动画,可以通过动画组来进行所有动画行为的统一控制,组中所有动画效果可以并发执行。

二、什么是UIView block动画?

CATransition

转场动画,继承自CAAnimation,主要是通过滤镜来进行动画的效果设置

1、UIView block动画的定义、本质及能做什么动画
CABasicAnimation

基础动画,继承自CAPropertyAnimation,通过属性控制动画的参数,只要初始状态和结束状态

2、UIView block动画的分类
CAKeyframeAnimation

关键帧动画,继承自CAPropertyAnimation,也是通过属性控制动画参数,但是与基础动画不同的是有多个控制状态,并且可以通过path来实现动画

(1)UIView block基础动画(UIView block属性动画的一种)
CASpringAnimation

弹簧动画,是在iOS 9中引入的,继承自CABasicAnimation,用于制作弹簧动画

①什么是UIView block基础动画?
动画使用

在使用动画之前,先补充个知识点—UIBezierPath,
这在动画使用的过程中会经常用到

②如何使用UIView block基础动画?
核心动画

要使用核心动画,我们必须先了解下其属性,这里我们先看其遵守的协议<CAMediaTiming>

属性 说明
beginTime 指定动画开始的时间。开始延迟几秒的话,设置为CACurrentMediaTime() + 秒数 的方式即可
duration 动画的时长
speed 动画的速度
timeOffset 详细说明
repeatCount 动画重复的次数,如果要一直持续设置为HUGE_VALF即可
repeatDuration 设置动画的时间。在该时间内动画一直执行,不计次数
autoreverses 动画结束时是否执行逆动画
fillMode 分四种情况,分别为kCAFillModeForwardskCAFillModeBackwardskCAFillModeBothkCAFillModeRemoved,决定当前对象在非active时间段的行为,比如动画开始之前或者动画结束之

CAAnimation属性

属性 说明
timingFunction 速度控制函数,控制动画运行的节奏
removedOnCompletion 默认为YES,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为NO,不过还要设置fillModekCAFillModeForwards

关于fillMode的四种情况:

  • kCAFillModeRemoved 默认值,动画结束后,layer会恢复到之前的状态

  • kCAFillModeForwards
    当动画结束后,layer会一直保持着动画最后的状态,而removedOnCompletion的默认属性值是
    YES,所以为了使动画结束之后layer保持结束状态,应将removedOnCompletion设置为NO

  • kCAFillModeBackwards
    在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。

  • kCAFillModeBoth
    这个其实就是上面两个的合成,动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态

关于速度CAMediaTimingFunction控制的四种情况

  • kCAMediaTimingFunctionLinear:匀速,给你一个相对静态的感觉

  • kCAMediaTimingFunctionEaseIn:动画缓慢进入,然后加速离开

  • kCAMediaTimingFunctionEaseOut:动画全速进入,然后减速的到达目的地

  • kCAMediaTimingFunctionEaseInEaseOut:动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。

(2)UIView block关键帧动画(UIView block属性动画的一种)
属性动画

从上图中我们知道,属性动画是继承自核心动画,在其API中我们可以看到有如下函数和属性

+ (instancetype)animationWithKeyPath:(nullable NSString *)path;@property(nullable, copy) NSString *keyPath;

其中都有keyPath,这又是什么呢?这就是属性动画与动画组和转场动画不同之处。通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性的值进行修改,达到相应的动画效果。比如,指定@"opacity"keyPath,就修改CALayeropacity属性的值,以达到透明度变化的动画效果下面我们列举一些常用的animationWithKeyPath

常用值 说明 使用方式
transform 3D变换 [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)],直接进行3D变换
transform.scale 缩放 @ ,放大1.5倍
transform.scale.x 宽度缩放 @ ,宽放大1.5倍
transform.scale.y 高度缩放 @ ,高放大1.5倍
transform.rotation.x 围绕x轴旋转 @ ,x轴旋转180度
transform.rotation.y 围绕y轴旋转 @ ,y轴旋转180度
transform.rotation.z 围绕z轴旋转 @ ,z轴旋转180度
position 位置 [NSValue valueWithCGPoint:CGPointMake],中心点变为
opacity 透明度 @ ,透明度变为0.5
bounds 大小的改变 中心点保持不变 [NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)],大小变为
cornerRadius 圆角的设置 @ ,圆角设置为5
backgroundColor 背景颜色变换 [UIColor redColor].CGColor,背景改为红色
contents 可以改变layer展示的图片 [UIImage imageNamed:@"12.png"].CGImage,将UIView的展示图片改为12.png
strokeStart 从起始点开始变化 fromValue = 0toValue = 1,为CAShapeLayer的属性
strokeEnd 从结束的位置开始变化 fromValue = 1toValue = 0.5,为CAShapeLayer的属性
path 根据路径来改变 fromValue = (__bridge id)(start.CGPath);toValue = (__bridge id)((end.CGPath))
①什么是UIView block关键帧动画?
基础动画

基础动画是继承自属性动画,所以在使用的时候,我们最主要的就是通过属性来控制动画,比如设置初始值、结束值,当然还有核心动画的其他属性。

- showAnimation{ CAShapeLayer * circle = [CAShapeLayer layer]; circle.frame = self.view.bounds; // UIBezierPath * circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)) radius:self.normalSize.width/2 -1 startAngle:0 endAngle:2*M_PI clockwise:YES]; circle.path = circlePath.CGPath; circle.strokeColor = [UIColor blueColor].CGColor; circle.fillColor = nil; [self.view.layer addSublayer:circle]; //通过圆的strokeStart 改变来进行改变 CABasicAnimation * strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @; strokeStartAnimation.toValue = @; //通过圆的strokeEnd 改变来进行改变 CABasicAnimation * strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @0.5; strokeEndAnimation.toValue = @; //通过圆的transform.rotation.z 改变来进行改变 CABasicAnimation * rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotationAnimation.fromValue = @; rotationAnimation.toValue = @(-M_PI * 2); //组合动画 CAAnimationGroup * group = [CAAnimationGroup animation]; group.duration = 5; group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; group.animations = @[strokeStartAnimation,strokeEndAnimation,rotationAnimation]; [circle addAnimation:group forKey:nil]; }

在上面的基础动画代码中,我只用了最基础的两个属性,fromValuetoValue,而其它属性呢?由于后面用到了动画组,所以讲其它属性在动画组进行了设置。[circle addAnimation:group forKey:nil];这句代码中,key我设置的为nil,如果不设置为nil的时候,是什么意思呢?这个其实就是我们的动画设置了一个key,可以用来区别是哪一个动画,在后面我会举例说明。上面代码对应的效果如下:

威尼斯人官网 2baseAnimation.gif

②如何使用UIView block关键帧动画?
关键帧动画

关键帧动画也是属性动画,与基础动画最主要不同的是在两个参数上,NSArray *valuesCGPathRef path,通过这个我们可以知晓,关键帧动画可以设置多个控制状态如下:

//用value的方式进行展示动画- showKeyFrameAnimationWithValues{ CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; NSValue *key1 = [NSValue valueWithCGPoint:_beginPoint]; NSValue *key2 = [NSValue valueWithCGPoint:CGPointMake]; NSValue *key3 = [NSValue valueWithCGPoint:CGPointMake]; NSValue *key4 = [NSValue valueWithCGPoint:CGPointMake]; animation.values = @[key1,key2,key3,key4]; animation.duration = 5.0; animation.delegate = self;// animation.autoreverses = true;//是否按路径返回// animation.repeatCount = HUGE;//是否重复执行 animation.removedOnCompletion = NO;//执行后移除动画 animation.fillMode = kCAFillModeForwards; //存储位置 [animation setValue:key4 forKey:@"keyframeAnimationLocation"]; [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_fish"];}

而且还可以设置路径,这也是其最大的特点如下:

//用CGPathRef的方式进行展示动画- showKeyFrameAnimationWithPath{ CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:_fishImageView.layer.position]; //三次贝塞尔曲线 [path addCurveToPoint:CGPointMake controlPoint1:CGPointMake controlPoint2:CGPointMake(230, -100)]; animation.path = path.CGPath; animation.duration = 5.0; animation.delegate = self; [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_path_fish"];}

效果如下,这里就暂时只给出values的效果

威尼斯人官网 3keyanimation.gif

在上面的两个方法中,对layer设置了两个不同的key,分别为keyframeAnimation_fishkeyframeAnimation_path_fish前面我提到过,通过这个可以判断是哪一种动画,这里我们在动画结束的地方进行区分一下

- animationDidStop:(CAAnimation *)anim finished:flag{ if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_fish"]]) {// [CATransaction begin];// //禁用隐式动画// [CATransaction setDisableActions:YES]; _fishImageView.layer.position = [[anim valueForKey:@"keyframeAnimationLocation"] CGPointValue]; // //提交事务// [CATransaction commit]; } else if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_path_fish"]]) { }}
(3)UIView block过渡动画
动画组

动画组其实很简单,就是将许多动画组合在一起在上面的基础动画中,我也用到了动画组,下面再贴上一组动画组合效果

//发射- launchAnimation{ CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"]; animation1.fromValue = @; animation1.toValue = @; CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"]; animation2.fromValue = @; animation2.toValue = @; CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"position"]; animation3.fromValue = [NSValue valueWithCGPoint:_ballLayer.position]; animation3.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width - /2.0 , _ballLayer.position.y - 200)]; CAAnimationGroup *anima = [CAAnimationGroup animation]; anima.animations = @[animation1, animation2,animation3]; anima.duration = 1.0; anima.delegate = self; anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; anima.fillMode = kCAFillModeForwards; anima.removedOnCompletion = NO; [_ballLayer addAnimation:anima forKey:@"group_launch"];}

在后面的demo里有完整的代码,这里只是截取了部分代码效果如下:

威尼斯人官网 4groupanimation.gif

①什么是UIView block过渡动画?
转场动画

在了解转场动画之前,我们先了解其两个参数,通过这些参数,我们就能很清楚的了解其效果

  • type转场类型
转场动画类型 说明 常量 是否支持方向设置
公开API
fade 淡出 kCATransitionFade
movein 新视图移动到旧视图上面 kCATransitionMoveIn
push 新视图退出旧视图 kCATransitionPush
reveal 移开旧视图显示新的 kCATransitionReveal
私有API 苹果未公开的类型,但是目前还是可以用的 私有API只能通过下面的字符串进行访问
cube 立体翻转
oglFlip 翻转
suckEffect 收缩
rippleEffect 水滴波纹效果
pageCurl 向上翻页效果
pageUnCurl 向下翻页效果
cameraIrisHollowOpen 摄像头打开效果
cameraIrisHollowClose 摄像头关闭效果
  • subtype动画子类型
属性 说明
kCATransitionFromRight 从右
kCATransitionFromLeft 从左
kCATransitionFromTop 从顶部
kCATransitionFromBottom 从底部

在了解上面两个属性后,对应转场动画,就差不多了部分代码如下

- transition:next{ CATransition *transition = [CATransition animation]; transition.type = @"cube"; if  { transition.subtype = kCATransitionFromLeft; } else { transition.subtype = kCATransitionFromRight; } transition.duration = 1.0; _imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg",_currentIndex]]; [_imageView.layer addAnimation:transition forKey:@"transitionAnimation"];}

效果如下

威尼斯人官网 5transanimation.gif

②如何使用UIView block过渡动画?
弹簧动画

弹簧动画是在iOS 9后才出现的,在这之前,我们可以通过下面的方法来实现

[UIView animateWithDuration:5.0 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveLinear animations:^{ } completion:nil];

iOS
9后苹果公开了这一API,我们先对其中的属性进行分析,因为代码中有注释,所以就直接贴一部分代码

 //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 positionAnimation.mass = 0.1; //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 positionAnimation.damping = 2; //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 positionAnimation.stiffness = 50; //初始速率,动画视图的初始速度大小 //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反 positionAnimation.initialVelocity = -10;

关于弹簧动画,我也写了一个例子,效果如下

威尼斯人官网 6springanimation.gif

三、如何使用UIView block动画?(应用举例)

写在最后

关于核心动画,差不多就简单的介绍这么点,如有什么不对的还望各位多多指教,不甚感激。最后,附上Demo

1、UIView block基础动画举例
2、UIView block关键帧动画举例
3、UIView block过渡动画举例

一、UIView可动画属性列表

最普通的属性 说明
backgroundColor
frame 改位置和大小,一般使用transform的平移和缩放来代替
bounds 改大小,一般使用transform的缩放来代替
center 改位置,一般使用transform的平移来代替
显隐性属性 说明
hidden 注意这个属性不支持动画,最简单的可以通过alpha或背景色来代替实现
alpha
仿射变换属性 说明
transform 可用来做view的平移、缩放、旋转动画

二、什么是UIView block动画?

1、UIView block动画的定义、本质及能做什么动画
  • 定义:UIView block动画就是用来在view层做动画的一种动画机制

  • 本质:UIView
    block动画的本质就是对layer的隐式动画或显式动画做了一层封装,提供简洁的Api,方便我们开发者使用。
    具体来说UIView
    block基础动画是对layer的隐式动画做了封装(因为它们同样可以设置过渡效果/图层行为,显示动画的基础动画不能设置图层行为,当然显式动画的过渡动画也可以作用于可动画属性,但是后面讲到隐式动画应该会知道UIView
    block基础动画是对layer的隐式动画做了封装),UIView
    block关键帧动画是对layer的显示动画的关键帧动画做了封装,UIView
    block过渡动画是对layer的显示动画的过渡动画做了封装。

  • 能做什么动画:

    • 下面我们会提到UIView block动画可分为UIView block属性动画和UIView
      block过渡动画,而UIView block属性动画又可分为UIView
      block基础动画和UIView block关键帧动画。

    • UIView
      block属性动画能做什么动画:
      那么从UIView的可动画属性列表我们可以看出,UIView
      block属性动画可以用来对view做背景色变化的动画、view显隐性变化的动画以及view的平移、缩放和旋转的仿射变换动画
      三种场景下的动画,其中执行一次UIView
      block基础动画只能改变一个属性值一次,执行一次UIView
      block关键帧动画可以设置多个关键帧所以能改变一个属性值多次

    • UIView block过渡动画能做什么动画:威尼斯人官网,UIView
      block属性动画只能对UIView的可动画属性做动画,但是如果我们现在想要对view的非动画属性改变时(如label的文本,imageView的图片等)做动画,甚至是对view的某些行为(如view的添加和移除,两个view之间切换)做动画,那就只能使用过渡动画了。

  • 就此我们也就知道了为什么要引入UIView block动画:
    • 第一、当然就是UIView
      block动画是作用于view层,对layer的隐式动画或显式动画做了一层封装,提供简洁的Api,方便我们开发者使用;
    • 第二、UIView
      block属性动画可以帮助我们在改变view的可动画属性时能做动画效果。如果看到后面一篇隐式动画,我们会知道在改变layer的可动画属性时,即便我们什么都不做直接修改layer的属性值,这个改变的过程也会默认有一个动画,它就是隐式动画;但是当我们在改变view的可动画属性时,是没有隐式动画的,如果我们什么都不做,属性就会直接跳变到新值,所以为了达到改变view的属性时能有动画,我们就得使用UIView
      block动画来实现了。
    • 第三、UIView
      block过渡动画可以帮助我们在改变view的不可变属性或者对view做某些行为能做动画。
2、UIView block动画的分类

UIView block动画可分为UIView block属性动画和UIView
block过渡动画,而UIView block属性动画又可分为UIView
block基础动画和UIView block关键帧动画,接下来我们将分别介绍UIView
block基础动画
UIView block关键帧动画UIView block过渡动画

(1)UIView block基础动画
①什么是UIView block基础动画?

UIView block基础动画是UIView
block属性动画的一种,它用来对view的可动画属性做动画,但是执行一次UIView
block基础动画只能改变一个属性值一次,因为我们是一次性把属性值直接设置为目标值的
(如果要想改变多次属性的值,可以在动画结束后再开始一个基础动画再改一次属性值,如此循环,但有一个更简单的办法就是使用UIView
block关键帧动画,后面会说到)它主要分下面四种:

  • 最简洁的block基础动画

[UIView animateWithDuration:// 动画时长
                 animations:^{

                     // 要改变的属性
                 }];
  • 带动画完成回调的block基础动画

[UIView animateWithDuration:// 动画时长
                 animations:^{

                     // 要改变的属性
                 } completion:^(BOOL finished) {

                     // 动画完成的回调
                 }];
  • 可设置延时和自定义动画过渡效果的block基础动画

[UIView animateWithDuration:// 动画时长
                      delay:// 延时多长时间后开始执行动画
                    options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
                 animations:^{

                     // 要改变的属性
                 } completion:^(BOOL finished) {

                     // 动画完成的回调
                 }];

UIView block基础动画自定义过渡效果(UIViewAnimationOptions)枚举值如下:

  • 一般就设置下过渡动画效果和过渡动画时间曲线就可以了;

  • 如果和后面layer显式动画的过渡动画的type和subType对比一下,会发现这里的过渡动画效果是把layer显式动画的过渡动画的type和subType组合起来了,而且这里的过渡动画效果要比layer显式动画的过渡动画的效果少得多,只有淡入淡出、正面背面二维翻转、翻页效果三种而已。

UIViewAnimationOptionTransitionNone// 过渡动画效果:不使用过渡动画
UIViewAnimationOptionTransitionCrossDissolve//过渡动画效果:淡入淡出效果,和显示动画的过渡动画的“fade”一样
UIViewAnimationOptionTransitionFlipFromTop// 过渡动画效果:正面和背面的二维翻转效果,从上向下翻转
UIViewAnimationOptionTransitionFlipFromLeft// 过渡动画效果:正面和背面的二维翻转效果,从左向右翻转
UIViewAnimationOptionTransitionFlipFromBottom// 过渡动画效果:正面和背面的二维翻转效果,从下向上翻转
UIViewAnimationOptionTransitionFlipFromRight//过渡动画效果:正面和背面的二维翻转效果,从右向左翻转
UIViewAnimationOptionTransitionCurlUp// 过渡动画效果:翻页效果,从下往上翻页
UIViewAnimationOptionTransitionCurlDown// 过渡动画效果:翻页效果,从上往下翻页

UIViewAnimationOptionCurveEaseInOut// 过渡动画的缓冲曲线:动画慢进,逐渐加快,逐渐减慢,慢出(默认值)
UIViewAnimationOptionCurveEaseIn// 过渡动画的缓冲曲线:动画慢进,逐渐加快
UIViewAnimationOptionCurveEaseOut// 过渡动画的缓冲曲线:动画逐渐减慢,慢出
UIViewAnimationOptionCurveLinear// 过渡动画的缓冲曲线:动画匀速

UIViewAnimationOptionRepeat// 重复执行动画
UIViewAnimationOptionAllowUserInteraction// 执行动画期间,开启view的用户交互

UIViewAnimationOptionAutoreverse// 执行动画回路
UIViewAnimationOptionLayoutSubviews// 执行动画时布局子控件
UIViewAnimationOptionAllowAnimatedContent// 执行动画时重绘视图
UIViewAnimationOptionBeginFromCurrentState// 从当前状态开始执行动画
UIViewAnimationOptionShowHideTransitionViews// 显示视图时显示或隐藏而不是移除或添加
UIViewAnimationOptionOverrideInheritedOptions// 不继承父动画设置
UIViewAnimationOptionOverrideInheritedCurve// 忽略嵌套动画的曲线设置
UIViewAnimationOptionOverrideInheritedDuration// 忽略嵌套动画的执行时间设置
  • Spring动画:就是指在改变属性的时候,属性值会在目标值附近摆动,类似弹簧那种的弹性动画

[UIView animateWithDuration:// 动画时长
                      delay:// 延时多长时间后开始执行动画
     usingSpringWithDamping:// 弹性效果的阻尼:范围0~1,数值越小弹性效果越明显,震得越久才能停下来
      initialSpringVelocity:// 弹性效果的初始速度:数值越大开始弹性动画时初始速度越快
                    options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
                 animations:^{

                     // 要改变的属性
                 } completion:^(BOOL finished) {

                     // 动画完成的回调
                 }];
②如何使用UIView block基础动画?

我们只需要在UIView
block基础动画的animationsblock里直接把可动画属性改变为目标值就可以了。

(2)UIView block关键帧动画
①什么是UIView block关键帧动画?

上面说到了UIView block基础动画是UIView
block属性动画的一种,而此处的UIView block关键帧动画也是UIView
block属性动画的一种,它也是用来对view的可动画属性做动画的,只不过效果可能在某些场景下比基础动画要方便或者丰富一些,但是执行一次UIView
block关键帧动画可以设置多个关键帧所以能改变一个属性值多次,而不是一次性把属性值设置目标值

需要注意的是:UIView
block关键帧动画设置关键帧只能通过增加关键帧方法来设置,相当于layer显示动画的关键帧动画的数组关键帧法,这个是不支持路径关键帧法的。

  • UIView block关键帧动画

[UIView animateKeyframesWithDuration:// 动画时长
                               delay:// 延时多长时间后开始执行动画
                             options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
                          animations:^{

                              // 添加关键帧
                          } completion:^(BOOL finished) {

                              // 动画完成的回调
                          }];

UIView
block关键帧自定义过渡效果(UIViewKeyframeAnimationOptions)枚举值如下:

  • 一般就设置下过渡动画的运算模式就可以了,或者直接采取默认就可以了。

UIViewKeyframeAnimationOptionCalculationModeLinear// 运算模式:连续,默认
UIViewKeyframeAnimationOptionCalculationModeDiscrete// 运算模式:离散
UIViewKeyframeAnimationOptionCalculationModePaced// 运算模式:均匀执行
UIViewKeyframeAnimationOptionCalculationModeCubic// 运算模式:平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced// 运算模式:平滑均匀

UIViewKeyframeAnimationOptionRepeat = UIViewAnimationOptionRepeat// 重复执行动画
UIViewKeyframeAnimationOptionAllowUserInteraction = UIViewAnimationOptionAllowUserInteraction// 执行动画期间,开启view的用户交互

UIViewKeyframeAnimationOptionAutoreverse = UIViewAnimationOptionAutoreverse// 执行动画回路
UIViewKeyframeAnimationOptionLayoutSubviews = UIViewAnimationOptionLayoutSubviews// 执行动画时布局子控件
UIViewKeyframeAnimationOptionBeginFromCurrentState = UIViewAnimationOptionBeginFromCurrentState// 从当前状态开始执行动画
UIViewKeyframeAnimationOptionOverrideInheritedOptions  = UIViewAnimationOptionOverrideInheritedOptions// 不继承父动画设置
UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration// 忽略嵌套动画的执行时间设置
  • 增加关键帧的方法

[UIView addKeyframeWithRelativeStartTime:// 这一帧动画开始的时间点(占总时间的比例)
                        relativeDuration:// 这一帧动画的动画时长(占总时间的比例)
                              animations:^{

                                  // 要改变的属性
                              }];
②如何使用UIView block关键帧动画?

我们只需要在UIView
block关键帧动画的animationsblock里直接增加关键帧就可以了,再在增加关键帧方法的animationsblock里把可动画属性改变为目标值就可以了。

(3)UIView block过渡动画
①什么是UIView block过渡动画?

前面我们学习了UIView block基础动画和UIView
block关键帧动画,但我们知道它俩其实都是UIView
block属性动画,即只能用来对view的可动画属性做动画。那么如果我们现在想要对view的非动画属性改变时(如label的文本,imageView的图片等)做动画,甚至是对view的某些行为(如view的添加和移除,两个view之间切换)做动画,那就只能使用过渡动画了。

同时我们也可以看到,上面UIView block基础动画和UIView
block关键帧动画的某些方法里也提供了过渡效果那个配置,也就是说过渡动画也是可以作用于可动画属性的,但是还可以做可动画属性之外的很多效果。

过渡动画的过渡效果可参见UIView
block基础动画的过渡效果,是一模一样的。

  • 给单个视图的不可动画属性或视图行为添加过渡动画

[UIView transitionWithView:// 要做动画的视图
                  duration:// 动画时长
                   options:// 过渡动画效果
                animations:^{

                    // 要改变的不可动画属性或图层行为
                } completion:^(BOOL finished) {

                    // 动画完成的回调
                }];
  • 给两个视图切换时添加过渡动画

注意:

  • 这个方法的过渡效果是体现在fromView和toView的父视图上的
  • 这个方法不需要提前把fromView和toView都添在父视图上,只需要先添加fromView就可以了
  • 这个方法在动画过程中,会自动把fromView会从父视图中移除,并把toView添加到父视图上

[UIView transitionFromView:// 旧视图
                    toView:// 新视图
                  duration:// 动画时长
                   options:// 动画过渡效果
                completion:^(BOOL finished) {

                    // 动画完成时的回调
                }];
②如何使用UIView block过渡动画?

我们只需要根据场景是改变单个视图的不可动画属性或视图行为要添加过渡动画还是给两个视图切换时添加过渡动画选择相应的方法就可以了。

三、UIView的block动画应用举例

1、UIView block基础动画
  • 让一条弹幕从右往左飘过去
    (清单1.1)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (strong, nonatomic) UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.label = [[UILabel alloc] init];
    self.label.backgroundColor = [UIColor magentaColor];
    self.label.frame = CGRectMake(kScreenWidth, 100, kScreenWidth, 30);
    self.label.text = @"嘿Siri,你在哪儿?";
    [self.view addSubview:self.label];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    [UIView animateWithDuration:5 animations:^{

        self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
    }];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end
  • 漂完之后,我们改变下弹幕内容
    (清单1.2)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    [UIView animateWithDuration:5 animations:^{

        self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
    } completion:^(BOOL finished) {

        self.label.text = @"你在哪儿,我就在哪儿!";
    }];
}
  • 我们可以让弹幕匀速地飘过,而不是默认的easyInEasyOut
    (清单1.3)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    [UIView animateWithDuration:3 delay:0 options:(UIViewAnimationOptionCurveLinear) animations:^{

        self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
    } completion:^(BOOL finished) {

        self.label.text = @"你在哪儿,我就在哪儿!";
    }];
}
  • 让弹幕弹一弹
    (清单1.4)

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    [UIView animateWithDuration:3 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:5 options:(UIViewAnimationOptionCurveLinear) animations:^{

        self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
    } completion:^(BOOL finished) {

        self.label.text = @"你在哪儿,我就在哪儿!";
    }];
}

威尼斯人官网 7

1.gif

2、UIView block关键帧动画

类似FaceBook登录界面,登录失败那种输入框抖动的效果。要是使用基础动画的话,可能就得平移一次,再开一个基础动画再平移一次,得开好几个基础动画,关键帧动画的话就开一个动画就可以了,添关键帧就行了。

(清单1.5)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (strong, nonatomic) UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.label = [[UILabel alloc] init];
    self.label.backgroundColor = [UIColor cyanColor];
    self.label.frame = CGRectMake(0, 100, kScreenWidth, 30);
    self.label.text = @"请登录";
    [self.view addSubview:self.label];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    self.label.text = @"登录失败";

    [UIView animateKeyframesWithDuration:0.5 delay:0 options:(UIViewKeyframeAnimationOptionCalculationModePaced) animations:^{

        [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1/4.0 animations:^{

            self.label.transform = CGAffineTransformMakeTranslation(10, 0);
        }];
        [UIView addKeyframeWithRelativeStartTime:1/4.0 relativeDuration:1/4.0 animations:^{

            self.label.transform = CGAffineTransformMakeTranslation(-10, 0);
        }];
        [UIView addKeyframeWithRelativeStartTime:2/4.0 relativeDuration:1/4.0 animations:^{

            self.label.transform = CGAffineTransformMakeTranslation(10, 0);
        }];
        [UIView addKeyframeWithRelativeStartTime:3/4.0 relativeDuration:1/4.0 animations:^{

            self.label.transform = CGAffineTransformMakeTranslation(0, 0);
        }];
    } completion:^(BOOL finished) {

        NSLog(@"动画结束了");
    }];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

威尼斯人官网 8

1.gif

3、UIView block过渡动画
(1)给单个视图的不可动画属性或视图行为添加过渡动画
  • 切换imageView的图片和label的文本

(清单1.6)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (strong, nonatomic) UIImageView *imageView;
@property (strong, nonatomic) UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.imageView = [[UIImageView alloc] init];
    self.imageView.frame = CGRectMake(0, 64, kScreenWidth, kScreenWidth);
    self.imageView.image = [UIImage imageNamed:@"0.jpg"];
    [self.view addSubview:self.imageView];

    self.label = [[UILabel alloc] init];
    self.label.frame = CGRectMake(0, kScreenWidth + 100, kScreenWidth, 30);
    self.label.text = @"奥黛丽赫本";
    self.label.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.label];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    NSInteger num = arc4random()%7;

    // 改变imageView的图片,淡入淡出效果
    [UIView transitionWithView:self.imageView duration:3 options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveLinear) animations:^{

        self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg", num]];
    } completion:nil];

    // 改变label的文本,二维翻转效果
    [UIView transitionWithView:self.label duration:3 options:(UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionCurveLinear) animations:^{

        switch (num) {
            case 0:
                self.label.text = @"奥黛丽·赫本";
                break;
            case 1:
                self.label.text = @"苏菲·玛索";
                break;
            case 2:
                self.label.text = @"泰勒·斯威夫特";
                break;
            case 3:
                self.label.text = @"安妮·海瑟薇";
                break;
            case 4:
                self.label.text = @"娜塔丽·波特曼";
                break;
            case 5:
                self.label.text = @"凯拉·奈特利";
                break;
            case 6:
                self.label.text = @"杰西卡·阿尔芭";
                break;
        }
    } completion:nil];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

威尼斯人官网 9

1.gif

  • 淡入淡出的效果添加view
    (清单1.7)

//
//  ViewController.m
//  CoreAnimation
//
//  Created by 意一yiyi on 2017/11/13.
//  Copyright © 2017年 意一yiyi. All rights reserved.
//

#import "ViewController.h"

#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (strong, nonatomic) UIImageView *imageView;
@property (strong, nonatomic) UILabel *label;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.imageView = [[UIImageView alloc] init];
    self.imageView.frame = CGRectMake(0, 64, kScreenWidth, kScreenWidth);
    self.imageView.image = [UIImage imageNamed:@"0.jpg"];

    self.label = [[UILabel alloc] init];
    self.label.frame = CGRectMake(0, kScreenWidth + 100, kScreenWidth, 30);
    self.label.text = @"奥黛丽赫本";
    self.label.textAlignment = NSTextAlignmentCenter;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {

    [UIView transitionWithView:self.view duration:3 options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveLinear) animations:^{

        [self.view addSubview:self.imageView];
        [self.view addSubview:self.label];
    } completion:nil];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

威尼斯人官网 10

1.gif

(2)给两个视图切换时添加过渡动画
  • 例如切换登录和注册视图(当然这个也可以UIViewController的方法来替换,有同样的效果)

威尼斯人官网 11

1.gif

相关文章