视图UIView动画

在iOS中,图形可分为以下几个层次:
视图UIView动画_第1张图片

越上层,封装程度越高,动画实现越简洁越简单,但是自由度越低;反之亦然。本文着重介绍Core Animation层的基本动画实现方案。

在iOS中,展示动画可以类比于显示生活中的“拍电影”。拍电影有三大要素:演员+剧本+开拍,概念类比如下:

演员--->CALayer,规定电影的主角是谁
剧本--->CAAnimation,规定电影该怎么演,怎么走,怎么变换
开拍--->AddAnimation,开始执行

一、概念介绍

1、使用CALayer

CALayer代表一个层,它提供了一个+layer类方法来创建CALayer层。

提示:所有的UIView都有一个默认的CALayer,通过UIView的layer属性即可访问UIView上的CALayer层。

使用CALayer的步骤非常简单,具体如下:

  1. 创建一个CALayer;
  2. 设置CALayer的contents属性即可设置该CALayer所显示的内容,该属性通常可指定一个CGImage,即代表CALayer将要显示的图片。如果需要自行绘制CALayer所显示的内容,可为CALayer指定delegate属性,该属性值应该是一个实现CALayerDelegate非正式协议的对象,重写该协议中的drawLayer:inContext:方法,即可完成CALayer的绘制。
  3. 为CALayer设置backgroundColor(背景色)、frame(设置大小和设置)、position(位置)、anchorPoint(锚点)、borderXxx(设置边框相关属性)、shadowXxx(设置阴影相关属性)等属性;
  4. 将该CALayer添加到父CALayer中即可。

与CALayer显示相关的还有如下几个常用属性:

  • (1)、contents:该属性控制CALayer显示的内容;
  • (2)、contentsRect:该属性控制CALayer的显示区域,其属性值是一个形如(0.0,0.0,1.0,1.0)的CGRect结构体,其中,1.0代表CALayer完整的宽和高;
  • (3)、contentsCenter:该属性控制CALayer的显示中心,其属性值是一个形如(0.0,0.0,1.0,1.0)的CGRect结构体,其中1.0代表CALayer完整的宽和高。通过该属性,可以把CALayer分成#字形网格,该属性指定的区域位置位于#字形中心。如果指定contentsCenter的contentsGravity属性为缩放模式,那么该CALayer被分成#字形的网格的上、下区域值进行水平缩放,#字形的网格的左、右区域只进行垂直缩放,中间区域进行两个方法的缩放,四个角则不进行缩放;
  • (4)、contentsGravity:该属性是一个NSString类型的常量值,用于控制CALayer中内容的缩放、对齐方式,它支持kCAGravityCenter等表示中心、上、下、左、右等对齐方式的属性值,也支持kCAGravityResizeXxx表示缩放的属性值;

具体详情请查看CALayer层

2、Core Animation动画基础


使用Core Animation创建动画不仅简单,而且具有更好地性能,原因有如下两个:

  • (1)、Core Animation动画在单独的线程中完成,不会阻塞主线程;
  • (2)、Core Animation动画只会重绘界面上变化的部分(局部刷新);
    Core Animation动画的核心是CALayer,每个UIView都有自己的CALayer,而且每个CALayer都可以不断地添加子CALayer,CALayer所在的CALayer被称为父CALayer,CALayer的这种组织方式被称为Layer Tree(各Layer之间的结构就像一棵树)。

除此之外,Core Animation动画还涉及如下API:

  • (1)、CAAnimation:它是所有动画类的基类,它实现了CAMediaTiming协议,提供了动画的持续时间、数独和重复计数等。CAAnimation还实现了CAAction协议,该协议为CALayer动画触发的动作提供标准化响应;
  • (2)、CATransition:CAAnimation的子类,CAAnimation可通过预置的过渡效果来控制CALayer层的过渡动画;
  • (3)、CAPropertyAnimation:它是CAAnimation的一个子类,它代表一个属性动画,可通过+animationWithKeyPath:类方法来创建属性动画实例(程序一般创建该子类的实例),该方法需要指定一个CALayer支持动画的属性,然后通过它的子类(CABasicAnimation、CAKeyframeAnimation)控制CALayer的动画属性慢慢地改变,即可实现CALayer动画;
  • (4)、CABasicAnimation:CAPropertyAnimation的子类,简单控制CALayer层的属性慢慢改变,从而实现动画效果。很多CALayer层的属性值的修改默认会执行这个动画类。比如大小、透明度、颜色等属性;
  • (5)、CAKeyframeAnimation:CAPropertyAnimation的子类,支持关键帧的属性动画,该动画最大的特点在于可通过values属性指定多个关键帧,通过多个关键帧可以指定动画的各阶段的关键帧;
  • (6)、CAAnimationGroup:它是CAAnimation的子类,用于将多个动画组合在一起执行。

二、动画实现

1、使用UIView控制动画方式

实际上,控制UIView内子控件的过渡还有另一种方式,通过UIView的+ (void)beginAnimations:(NSString )animationID context:(void )context;与 + (void)commitAnimations;方法控制,——如果子组件的过渡动画不是特别复杂,只需要实现一些简单的动画,即可通过这种方式控制。步骤如下:

  1. 调用UIView的+ (void)beginAnimations:(NSString )animationID context:(void )context;方法开始动画;
  2. 调用UIView的+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;设置动画类型、+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;方法设置动画的变化曲线。除此之外,UIView还提供了系列setAnimationXxx方法来设置动画的持续时间、延迟时间、重复次数等属性;
  3. 调用UIView的+ (void)commitAnimations;方法提交动画;

上面的+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache;方法用于控制UIView的过渡动画的动画方式,它支持如下动画方式:

  • ①、UIViewAnimationTransitionNone:不适用动画;
  • ②、UIViewAnimationTransitionFlipFromLeft:指定从左边滑入的动画过渡方式;
  • ③、UIViewAnimationTransitionFlipFromRight:指定从右边滑出的动画过渡方式;
  • ④、UIViewAnimationTransitionCurlUp:指定“翻开书页”的动画过渡方式;
  • ⑤、UIViewAnimationTransitionCurlDown:指定“放下书页”的动画过渡方式;

另:+ (void)setAnimationCurve:(UIViewAnimationCurve)curve;方法用于控制动画的变化曲线,也就是控制动画的变化速度,该方法支持如下几种变化速度:

  • ①、UIViewAnimationCurveEaseInOut:动画先比较缓慢,然后逐渐加快;
  • ②、UIViewAnimationCurveEaseIn:动画逐渐变慢;
  • ③、UIViewAnimationCurveEaseOut:动画逐渐加快;
  • ④、UIViewAnimationCurveLinear:匀速动画;

例如:

- (void)curl:(UIButton *)sender{
    //开始执行动画
    [UIView beginAnimations:@"animation" context:nil];
    [UIView setAnimationDuration:1.0f];
    //控制UIView内过渡动画的类型
    [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
    //设置动画的变化曲线
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    //交换视图控制器所显示的UIView中两个子控件的位置
    [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
    [UIView commitAnimations];
}

2、CAAnimation

CAAnimation提供了如下属性和方法:

  • (1)、BOOL removedOnCompletion;该属性用于指定该动画完成时是否从目标CALayer上删除该动画
  • (2)、CAMediaTimingFunction *timingFunction;该属性用于指定一个CAMediaTimingFunction对象,该对象负责控制动画边长的步长;
  • (3)、- (void)animationDidStart:(CAAnimation *)anim;该动画开始时将会回调该方法。开发者可以重写该方法执行自定义处理;
  • (4)、- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;该动画结束时将会回调该方法。开发者可以重写该方法执行自定义处理;

3、 CAMediaTiming

  • (1)、 @property CFTimeInterval beginTime;

    • ①、如果一animation是在一个animation group中,则beginTime就是其parent object——animation group 开始的一个偏移。如果一个animation的beginTime为5,则此动画再group animation开始之后的5秒再开始动画
    • ②、如果一个animation是直接添加再layer上,beginTime同样是其parent object——layer开始的一个偏移,但是一个layer的beginning是一个过去的时间,因此不能简单的设置beginTime为5去延迟动画5s之后开始,因为可能layer的beginning加上5s之后也是过去的时间,因此,当要延迟一个添加layer上的动画的时候,需要定义一个addTime,先获取addTime如下:

      CFTimeInterval addTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
      

      然后延迟delay秒:

      animation.beginTime = addTime + delay;
      
  • (2)、 @property CFTimeInterval duration;设置时间;

    注意,我们设置的duration可能和动画进行的真是duration不一样,这个依赖于superLayer的time space或者就是speed;

  • (3)、 @property float speed;动画速度;

    注意:如果一个动画A:duration为1秒,speed为1;而另一个动画B:duration为2秒,speed为2。则这两个动画的效果是相同的;前提它们的super layer相同;

  • (4)、 @property CFTimeInterval timeOffset;
    假设一个3s的动画,它的状态为t0,t1,t2,t3,当没有timeOffset的时候,正常的状态序列应该为:t0->t1->t2->t3;当设置timeOffset为1的时候状态序列就变为:t1->t2->t3->t0;同理当timeOffset为2的时候状态序列就变味t2->t3->t0->t1;

  • (5)、 @property float repeatCount;动画重复次数;

  • (6)、 @property CFTimeInterval repeatDuration;动画重复时间;

  • (7)、 @property BOOL autoreverses;动画结束后是否返回到原来的位置;

4、使用CATransition控制过渡动画

CATransition通常用于通过CALayer控制UIView内子控件的过度画面,比如,删除子控件、添加子控件、切换两个子控件。继承CAAnimation

使用CATransition控制UIView内子控件的过度画面的步骤如下:

  1. 创建CATransition对象;
  2. 为CATransition设置type和subtype两个属性,其中,type指定动画类型,subtype指定动画移动方向;
  3. 如果不需要动画执行整个过程(就是只要动画执行到中间部分就停止),可以指定startProgress(动画的开始速度)、endProgress(动画的结束进度)属性;
  4. 调用UIView的layer属性的addAnimation:forKey:方法控制该UIView内子控件的过渡动画。addAnimation:forKey:方法的第一个参数为CAAnimation对象,第二个参数用于为该动画对象执行一个唯一标识。

提示:CATransition继承了CAAnimation,因此也支持指定CAAnimation的removedOnCompletion等属性;

CATransition属性如下:

  • (1)、 @property(copy) NSString *type;
    CATransition的type属性用于控制动画类型,它支持如下值(每个值代表一种类型的动画)。

    • ①、NSString * const kCATransitionFade;通过渐隐效果控制子组件的过渡。这是默认的属性值;
    • ②、NSString * const kCATransitionMoveIn;通过移入动画控制子组件的过渡;
    • ③、NSString * const kCATransitionPush;通过推入动画控制子组件的过渡;
    • ④、NSString * const kCATransitionReveal;通过揭开动画控制子组件的过渡;
      除此之外,该属性该支持如下私有动画:
    • ①、cube:通过立方体旋转动画控制子组件的过渡;
    • ②、suckEffect:通过收缩动画(就像被吸入的效果)控制子组件的过渡;
    • ③、oglFlip:通过翻转动画控制子组件的过渡;
    • ④、rippleEffect:通过水波动画控制子组件的过渡;
    • ⑤、pageCurl:通过页面揭开动画控制子组件的过渡;
    • ⑥、pageUnCurl:通过放下页面动画控制子组件的过渡;
    • ⑦、cameraIrisHollowOpen:通过镜头打开动画控制子组件的过渡;
    • ⑧、cameraIrisHollowClose:通过镜头关闭动画控制子组件的过渡;
  • (2)、 @property(nullable, copy) NSString *subtype;
    CATransition的subtype属性用于控制动画方向,它支持如下值:

    • ①、NSString * const kCATransitionFromRight;
    • ②、NSString * const kCATransitionFromLeft;
    • ③、NSString * const kCATransitionFromTop;
    • ④、 NSString * const kCATransitionFromBottom;

例如:

- (void)oglFlip:(UIButton *)sender{
    //开始执行动画
    CATransition* transition = [CATransition animation];
    transition.duration = 2.0f;
    //通过翻转动画控制子组件的过渡;
    transition.type = @"oglFlip";
    //指定动画方向,从下向上
    transition.subtype = kCATransitionFromBottom;
    [self.view.layer addAnimation:transition forKey:@"animation"];
    [self.view exchangeSubviewAtIndex:0 withSubviewAtIndex:1];
}

视图UIView动画_第2张图片

5、使用属性动画(CAPropertyAnimation)

属性动画由CAPropertyAnimation代表,该对象用于控制CALayer的动画属性(所有支持数值型属性值的属性几乎都可作为动画属性)持续改变,当CALayer的动画属性持续改变时,CALayer的外观就会持续改变——用户看上去就变成了动画。

CAPropertyAnimation提供了如下类方法来创建属性动画:

方法+ (id)animationWithKeyPath:(NSString *)path;仅需要一个参数,该参数只是一个字符串类型的值,指定CALayer的动画属性名,设置该属性动画控制CALayer的哪个动画属性持续改变。

除此之外,CAPropertyAnimation还支持如下属性:

  • (1)、@property(nullable, copy) NSString *keyPath;
    该属性值返回创建CAPropertyAnimation时指定的参数;
  • (2)、@property(getter=isAdditive) BOOL additive;
    该属性指定该属性动画是否以当前动画效果为基础;
  • (3)、@property(getter=isCumulative) BOOL cumulative;
    该属性指定动画是否为累加效果;
  • (4)、@property(nullable, strong) CAValueFunction *valueFunction;
    该属性值是一个CAValueFunction对象,该对象负责对属性改变的插值计算。系统已经提供了默认的插值计算方式,因此一般无需指定该属性。

如果要控制CALayer的位移动画,直接使用属性动画控制CALayer的postion持续改变即可。如果要控制该CALayer的缩放、旋转、斜切等效果,则需要控制如下属性。

  • (1)、affineTransform:该属性值指定一个CGAffineTransform对象,该对象代表对CALayer执行X、Y两个维度(也就是平面)上的旋转、缩放、位移、斜切、镜像等变换矩阵;
  • (2)、transform:该属性值指定一个CATransform3D对象,该对象代表对CALayer指定X、Y、Z三个维度(也就是三维空间)中的旋转、缩放、位移、斜切、镜像等变换矩阵。

一般来说,可使用Core Animation提供了如下属性来创建三维变换矩阵:

  • (1)、bool CATransform3DIsIdentity (CATransform3D t);判断t矩阵是否为单位矩阵;
  • (2)、bool CATransform3DEqualToTransform (CATransform3D a, CATransform3D b);判断连个变换矩阵是否相等;
  • (3)、CATransform3D CATransform3DMakeTranslation (CGFloat tx, CGFloat ty, CGFloat tz);创建在X方向上移动tx、Y方向上移动ty、Z方向上移动tz的变换矩阵;
  • (4)、CATransform3D CATransform3DMakeScale (CGFloat sx, CGFloat sy, CGFloat sz);创建在X方向上缩放sx、Y方向上缩放sy、Z方向上缩放sz的变换矩阵;
  • (5)、CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z);创建基于指定旋转轴旋转angle弧度的变换。其中参数x、y、z的值用于确定旋转轴的方向。比如(1,0,0)指定旋转轴为X轴,(1,1,0)指定以X轴、Y周夹角的中线为旋转轴;
  • (6)、CATransform3D CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz);以已有t变换矩阵为基础进行位移变换;
  • (7)、CATransform3D CATransform3DScale (CATransform3D t, CGFloat sx, CGFloat sy, CGFloat sz);以已有t变换矩阵为基础执行缩放变换;
  • (8)、CATransform3D CATransform3DRotate (CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z);以已有的t变换为基础执行旋转变换;
  • (9)、CATransform3D CATransform3DConcat (CATransform3D a, CATransform3D b);对a变换矩阵执行累加;
  • (10)、CATransform3D CATransform3DInvert (CATransform3D t);对已有的t变换执行反转;
  • (11)、CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);将CGAffineTransform矩阵包装成CATransform3D变换矩阵,该CATransform3D也只有X、Y维度的变换;
  • (12)、bool CATransform3DIsAffine (CATransform3D t);如果t变换只是一个CGAffineTransform矩阵,则该函数返回YES;
  • (13)、CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);获取t变换矩阵所包含的CGAffineTransform变换矩阵。

使用属性动画控制CALayer的执行动画创建属性动画:

  • ①、利用animationWithKeyPath类方法创建属性动画;
  • ②、如果使用CABasicAnimation属性动画,则可指定fromValue、toValue两个属性值,其中,formValue指定动画属性开始时的属性值,toValue指定动画属性结束时的属性值;
  • ③、如果使用CAKeyframeAnimation属性动画,则指定values属性值,该属性值是一个NSArray属性,其中第一个元素指定动画属性开始时的属性值,toValue指定动画属性结束时的属性值,其他数组元素指定动画变化过程中的属性值。

    提示:CABasicAnimation,CAKeyframeAnimation都继承了CAPropertyAnimation,他们都是
    属性动画,只是CABasicAnimation只能指定动画属性的开始值和结束值,该CALayer的动画属性
    就由开始值变化到结束值;而CAKeyframeAnimation则可为动画属性指定多个值,该CALayer的
    动画属性就从values的第一个属性值开始,依次经历每个属性值,知道变成最后一个属性值。
    
  • ④、调用CALayer的addAnimation:forKey:添加动画即可;

CALayer为动画支持提供了如下方法:

  • (1)、- (void)addAnimation:(CAAnimation )anim forKey:(NSString )key;为该CALayer添加一个动画,第二个参数为该动画指定key(相当于该动画的唯一标识,这样保证每个CALayer可绑定多个动画对象);
  • (2)、- (CAAnimation )animationForKey:(NSString )key;控制该CALayer执行指定key所对应的动画;
  • (3)、- (void)removeAllAnimations;删除CALayer上添加的所有动画;
  • (4)、- (void)removeAnimationForKey:(NSString *)key;根据key删除该CALayer上指定的动画;
  • (5)、- (NSArray *)animationKeys;获取CALayer上添加的所有动画key所组成的数组;

1)、CABasicAnimation

  • ①、移动动画
- (void)move:(UIButton *)sender{
    //获取animationLayer的位置
    CGPoint fromPoint = animationLayer.position;
    CGPoint toPoint = CGPointMake(fromPoint.x + 80, fromPoint.y);
    //创建不断改变CALayer的position属性的属性动画
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position"];
    //设置动画开始的属性值
    anim.fromValue = [NSValue valueWithCGPoint:fromPoint];
    //设置动画结束的属性值
    anim.toValue = [NSValue valueWithCGPoint:toPoint];
    anim.duration = 2;
    animationLayer.position = toPoint;
    anim.removedOnCompletion = YES;
    //添加动画到图层,注意key相当于给动画进行命名,以后获得该图层时可以使用此名称获取
    [animationLayer addAnimation:anim forKey:@"KCBasicAnimation_Translation"];
}
  • ②、旋转动画
- (void)rotationAnimation:(UIButton *)sender{
    //1.创建动画并指定动画属性
    CABasicAnimation *basicAnimation=[CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    //2.设置动画属性初始值、结束值
    // basicAnimation.fromValue=[NSNumber numberWithInt:M_PI_2];
    basicAnimation.toValue=[NSNumber numberWithFloat:M_PI_2*3];
    //设置其他动画属性
    basicAnimation.duration=6.0;
    basicAnimation.autoreverses=true;//旋转后再旋转到原来的位置
    //4.添加动画到图层,注意key相当于给动画进行命名,以后获得该动画时可以使用此名称获取
    [animationLayer addAnimation:basicAnimation forKey:@"KCBasicAnimation_Rotation"];
}
  • ③、缩小放大
- (void)scaleAnimation:(UIButton *)sender{
    CABasicAnimation *pulse = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    pulse.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    pulse.duration = 0.5 + (rand() % 10) * 0.05;
    pulse.repeatCount = 1;
    pulse.autoreverses = YES;
    pulse.fromValue = [NSNumber numberWithFloat:.8];
    pulse.toValue = [NSNumber numberWithFloat:1.2];
    [animationLayer addAnimation:pulse forKey:nil];
}

2)、CAKeyframeAnimation

- (void)scale:(UIButton *)sender{
    //创建不断改变CALayer的transform属性的属性动画
    CAKeyframeAnimation* anim = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    //设置CAKeyframeAnimation控制transform属性依次经过的属性值
    anim.values = [NSArray arrayWithObjects:[NSValue valueWithCATransform3D:imageLayer.transform],[NSValue valueWithCATransform3D:CATransform3DScale(imageLayer.transform, 0.2, 0.2, 1)],[NSValue valueWithCATransform3D:CATransform3DScale(imageLayer.transform, 2, 2, 1)],[NSValue valueWithCATransform3D:imageLayer.transform], nil];
    anim.duration = 5;
    anim.removedOnCompletion = YES;
    [imageLayer addAnimation:anim forKey:nil];
}

注意:path其他还有transform.scale = 比例转换、transform.scale.x = 宽的比例转换、transform.scale.y = 高的比例转换、transform.rotation.z = 平面圆的旋转、opacity = 透明度、backgroundColor=背景颜色、cornerRadius=圆角。。。

6、使用CAAnimationGroup控制动画方式

- (void)group:(UIButton *)sender{
    CGPoint fromPoint = imageLayer.position;
    CGPoint toPoint = CGPointMake(fromPoint.x + 80, fromPoint.y);
    //创建不断改变CALayer的position属性的属性动画
    CABasicAnimation* moveAnim = [CABasicAnimation animationWithKeyPath:@"positon"];
    //设置动画开始的属性值
    moveAnim.fromValue = [NSValue valueWithCGPoint:fromPoint];
    //设置动画结束的属性值
    moveAnim.toValue = [NSValue valueWithCGPoint:toPoint];
    moveAnim.duration = 6;
    imageLayer.position = toPoint;
    moveAnim.removedOnCompletion = YES;
    //--------------------
    //创建不断改变CALayer的transform属性的属性动画
    CABasicAnimation* transformAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
    CATransform3D fromValue = imageLayer.transform;
    //设置动画开始的属性值
    transformAnim.fromValue = [NSValue valueWithCATransform3D:fromValue];
    //创建在X、Y两个方向上缩放为0.5的变换矩阵
    CATransform3D scaleValue = CATransform3DScale(fromValue, 0.5, 0.5, 1);
    //绕Z轴旋转180度的变换矩阵
    CATransform3D rotateValue = CATransform3DRotate(fromValue, M_PI, 0, 0, 1);
    //计算两个变换矩阵的和
    CATransform3D toValue = CATransform3DConcat(scaleValue, rotateValue);
    //设置动画结束的属性值
    transformAnim.toValue = [NSValue valueWithCATransform3D:toValue];
    //动画效果累加
    transformAnim.cumulative = YES;
    //动画重复执行次数,旋转360度
    transformAnim.repeatCount = 2;
    transformAnim.duration = 6;
    //位移、缩放、旋转组合起来执行
    CAAnimationGroup* animGroup = [CAAnimationGroup animation];
    animGroup.animations = [NSArray arrayWithObjects:moveAnim,transformAnim, nil];
    animGroup.duration = 6;
    [imageLayer addAnimation:animGroup forKey:nil];
}

三、关于CAShapeLayer+ CAGradientLayer的动画

1、设定动画基础

- (void)viewDidLoad {
    [super viewDidLoad];
    CGFloat pathBorder = WIN_WIDTH/2;
    UIView* bgView = [[UIView alloc]initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, self.view.frame.size.height - 20)];
    bgView.backgroundColor = [UIColor redColor];
    [self.view addSubview:bgView];
    //画出一个完成的进度的背景轨道
    //创建一个路径图层
    trackLayer = [CAShapeLayer layer];
    trackLayer.frame = CGRectMake(0, 100, pathBorder, pathBorder);
    trackLayer.fillColor = [[UIColor clearColor] CGColor];
    //指定path的渲染颜色
    trackLayer.strokeColor = [[UIColor redColor] CGColor];
    //背景同学你就甘心做背景吧,不要太明显了,透明度小一点
    trackLayer.opacity = 1;
    //指定线的边缘是圆的
    trackLayer.lineCap = kCALineCapRound;
    //线的宽度
    trackLayer.lineWidth = 4;
    //上面说明过了用来构建圆形
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(pathBorder/2, pathBorder/2) radius:(pathBorder-4)/2 startAngle:degreesToRadians(-360) endAngle:degreesToRadians(0) clockwise:YES];
    //把path传递給layer,然后layer会处理相应的渲染,整个逻辑和CoreGraph是一致的。
    trackLayer.path =[path CGPath];
    [bgView.layer addSublayer:trackLayer];

    //创建背景图层
    gradientLayer =  [CAGradientLayer layer];
    [gradientLayer setColors:[NSArray arrayWithObjects:
                              (id)[[[UIColor blackColor] colorWithAlphaComponent:1] CGColor],
                              (id)[[[UIColor yellowColor] colorWithAlphaComponent:1] CGColor],
                              (id)[[[UIColor purpleColor] colorWithAlphaComponent:1] CGColor],
                              (id)[[UIColor whiteColor] CGColor],
                              nil]];
    gradientLayer.frame = bgView.bounds;
    [gradientLayer setLocations:[NSArray arrayWithObjects:
                                 [NSNumber numberWithFloat:0.0],
                                 [NSNumber numberWithFloat:0.3],
                                 [NSNumber numberWithFloat:0.8],
                                 [NSNumber numberWithFloat:1.0],
                                 nil]];
    [gradientLayer setStartPoint:CGPointMake(0, 0.5)];
    [gradientLayer setEndPoint:CGPointMake(1, 0.5)];
    [bgView.layer addSublayer:gradientLayer];
    [gradientLayer setMask:trackLayer]; //用progressLayer来截取渐变层

    UIButton* btn = [UIButton buttonWithType:UIButtonTypeCustom];
    btn.frame = CGRectMake(0, 20, self.view.frame.size.width, 40);
    [btn addTarget:self action:@selector(startGreenHeadAnimation) forControlEvents:UIControlEventTouchUpInside];
    [btn setTitle:@"动画跳转" forState:UIControlStateNormal];
    [self.view addSubview:btn];
}

2、移动路径图层动画

- (void)startGreenHeadAnimation{
    //动画
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.duration = 2;
    //获取animationLayer的位置
    CGPoint fromPoint = trackLayer.position;
    CGPoint toPoint = CGPointMake(fromPoint.x + WIN_WIDTH/2, fromPoint.y);
    //设置动画开始的属性值
    animation.fromValue = [NSValue valueWithCGPoint:fromPoint];
    //设置动画结束的属性值
    animation.toValue = [NSValue valueWithCGPoint:toPoint];
    trackLayer.position = toPoint;
    animation.removedOnCompletion = YES;
    [trackLayer addAnimation:animation forKey:@"position"];
}

视图UIView动画_第3张图片

总结:移动路径图层,背景图层不会跟着移动;

3、移动背景图层动画

- (void)startGreenHeadAnimation{
    //动画
    CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"position"];
    animation1.duration = 2;
    //获取animationLayer的位置
    CGPoint fromPoint1 = gradientLayer.position;
    CGPoint toPoint1 = CGPointMake(fromPoint1.x + WIN_WIDTH/2, fromPoint1.y);
    //设置动画开始的属性值
    animation1.fromValue = [NSValue valueWithCGPoint:fromPoint1];
    //设置动画结束的属性值
    animation1.toValue = [NSValue valueWithCGPoint:toPoint1];
    gradientLayer.position = toPoint1;
    animation1.removedOnCompletion = YES;
    [gradientLayer addAnimation:animation1 forKey:@"position"];
}

视图UIView动画_第4张图片

总结:移动背景图层,路径图层跟着移动;

4、同时移动路径图层和背景图层

- (void)startGreenHeadAnimation{

    //动画
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
    animation.duration = 2;
    //获取animationLayer的位置
    CGPoint fromPoint = trackLayer.position;
    CGPoint toPoint = CGPointMake(fromPoint.x + WIN_WIDTH/2, fromPoint.y);
    //设置动画开始的属性值
    animation.fromValue = [NSValue valueWithCGPoint:fromPoint];
    //设置动画结束的属性值
    animation.toValue = [NSValue valueWithCGPoint:toPoint];
    trackLayer.position = toPoint;
    animation.removedOnCompletion = YES;
    [trackLayer addAnimation:animation forKey:@"position"];

    //动画
    CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"position"];
    animation1.duration = 2;
    //获取animationLayer的位置
    CGPoint fromPoint1 = gradientLayer.position;
    CGPoint toPoint1 = CGPointMake(fromPoint1.x - WIN_WIDTH/2, fromPoint1.y);
    //设置动画开始的属性值
    animation1.fromValue = [NSValue valueWithCGPoint:fromPoint1];
    //设置动画结束的属性值
    animation1.toValue = [NSValue valueWithCGPoint:toPoint1];
    gradientLayer.position = toPoint1;
    animation1.removedOnCompletion = YES;
    [gradientLayer addAnimation:animation1 forKey:@"position"];
}

视图UIView动画_第5张图片

你可能感兴趣的:(动画,UIView)