zoukankan      html  css  js  c++  java
  • iOS动画——CoreAnimation

    CoreAnimation
    在我之前的UIKit动画里面简单的提了一句CoreAnimation动画,其实大家别看它类库名种有个animation,实际上animation在这个库中只占有很小的地位。

    像我们经常用的边框、圆角、阴影、锚点等等这些属性都是有CA提供的。

    在说CA动画前,我们先说一下CALayer这个类,CALayer可以叫做图层,UIView是视图。对别CALayer和UIView它们之间最大的差别在于CALayer是不处理交互的,比如点击事件等。

    实际上UIView是CALayer的高层封装罢了,UIView的现实、绘图、动画等等都是封装的CALayer,在CALayer中有个重要的属性叫做affineTransform(放射变换),其实它和UIView中的transform是一摸一样的,返回的都是

    CAAffineTransform。当你改变过一个view.transform属性或者view.layer.transform的时候需要恢复默认状态的话,记得先把他 们重置可以使用

    view.transform = CGAffineTransformIdentity,或者view.layer.transform =CATransform3DIdentity,假设你一直不断的改变一个view.transform的属性,而每次改变之前没有重置的话,你会发现后来 的改变和你想要的发生变化了,不是你真正想要的结果。

    现在大家对CALayer有了初步的认识,我们一起看看动画在CA中是如何使用的。

    隐式动画

    其实我们只要修改CALayer中和动画有关的属性,就算我们不写动画代码,在运行的时候也是会有动画效果的。这叫做隐式动画,也就是我们并没有明显的调用。

    下面我们看个例子

    @interface ViewController ()
    {
        CALayer *_viewLayer;
    }
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        _viewLayer = [CALayer layer];
        _viewLayer.frame = CGRectMake(0, 0, 100, 100);
        [_viewLayer setBackgroundColor:[UIColor greenColor].CGColor];
        _viewLayer.opacity = 0.25;
        [self.view.layer addSublayer:_viewLayer];
        
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    - (IBAction)click:(id)sender
    {
        CGAffineTransform moveTransforam = CGAffineTransformMakeTranslation(180, 200);
        [_viewLayer setAffineTransform:moveTransforam];
        _viewLayer.opacity = 1;
    }

    把这段代码输入,点击按钮,你就会发现view逐渐的变的不透明,并且位置也发生了改变。

    显式动画

    在显式动画中,不需要修改属性和调用动画执行方法,只需要通过CABasicAnimation逐个定义就行了,每个对象有持续时间、重复次数等属性,然后使用addAnimation:forkey:方法分别将每个动画用到图层的特定属性中。

    能够做动画的图层属性有以下:

    opacity;

    transform.scale;

    transform.scale.x;

    transform.scale.y;

    transform.rotation.z;

    opacity;

    margin;

    zPosition;

    backgroundColor;

    cornerRadius;

    bounds;

    contents;

    contentsRect;

    frame;

    hidden;

    mask;

    masksToBounds;

    position;

    shadowColor;

    shadowOffset;

    shadowOpacity;

    shadowRadius;

    下面我们看一个显式动画的例子:

        CABasicAnimation *opAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
        opAnim.duration = 3.0;
        opAnim.fromValue = [NSNumber numberWithFloat:.25];
        opAnim.toValue = [NSNumber numberWithFloat:1.0];
        opAnim.cumulative = NO;
        opAnim.repeatCount = 2;
        opAnim.fillMode = kCAFillModeForwards;
        opAnim.removedOnCompletion = NO;
        [_viewLayer addAnimation:opAnim forKey:@"animateOpacity"];
        
        CGAffineTransform moveTransform = CGAffineTransformMakeTranslation(180, 200);
        CABasicAnimation *moveAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
        moveAnim.duration = 6.0;
        moveAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeAffineTransform(moveTransform)];
        moveAnim.fillMode = kCAFillModeForwards;
        moveAnim.removedOnCompletion = NO;
        moveAnim.delegate = self;
        moveAnim.repeatCount = 2;
        [_viewLayer addAnimation:moveAnim forKey:@"animateTransform"];

    把click中的代码换成上面的代码,会发现视图慢慢变得不透明,过程中执行两次。

    下面看一下CABasicAnimation属性有哪些作用:

    属性 描述
    duration 动画持续时间
    fromValue 动画的属性起始值
    toValue 动画的属性目标值
    cumulative 是否保留上次动画的值
    repeatCount 重复次数
    fillMode 使用动画后不在返回原位置
    removeOnCompletion 动画完成后移除动画状态
    delegate 动画代理

    这里简单说一下cumulative,上面例子如果cumulative设为YES的话,就不会执行第二次的opacity的变化了,因为保留了动画的状态。

    fillMode和removeOnCompletion一起用使得动画结束后视图还在结束的位置,否则视图会回到原始位置。

    不过这里说一下,虽然我们看到的值是已经变了,但是实际上原始值并不会因为做了动画而改变,只不过是affineTransform变了,如果要多次做affineTransform就要像上面说的,需要让它恢复初始值就不会出问题。

    然后再来看看delegate,不过代理不是CABasicAnimation的,也不是它的父类CAPropertyAnimation的,而是它父类的父类CAAnimation的!

    代理方法如下

    - (void)animationDidStart:(CAAnimation *)anim;
    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;

    一个是动画是在动画开始时的回调,另一个是在动画结束后的回调。

    关键帧动画

    关键帧动画其实也可以说又分两种,一种是帧动画一种是路径动画。

    帧动画,不多说先看例子

        CAKeyframeAnimation *opAnim = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
        opAnim.duration = 6.0;
        opAnim.values = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.25],[NSNumber numberWithFloat:0.75],[NSNumber numberWithFloat:1.0], nil];
        opAnim.keyTimes = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],[NSNumber numberWithFloat:0.5],[NSNumber numberWithFloat:1.0], nil];
        
        opAnim.fillMode = kCAFillModeForwards;
        opAnim.removedOnCompletion = NO;
        opAnim.delegate = self;
        [_viewLayer addAnimation:opAnim forKey:@"animateOpacity"];

    这里我们对透明度做动画,分别在values和keyTimes里面设置了到达某一时间应该到达的值,也就是通过这些值影响了在不同时间动画的状态不一样。大家应该还记得在之前的UIKit动画中,介绍过keyframe开始和持续时间的含义,它们都是总时间的百分比。

    路径动画

    路径动画动画其实可以说是特殊的帧动画,首先动画的对象属性是position,然后每一帧的速率都相同,用多线程的概念来讲大概就是串行执行动画的意思。

        CGMutablePathRef path = CGPathCreateMutable();
        CGPathMoveToPoint(path, NULL, 160.f, 100.f);
        CGPathAddLineToPoint(path, NULL, 100.f, 280.f);
        CGPathAddLineToPoint(path, NULL, 260.f, 170.f);
        CGPathAddLineToPoint(path, NULL, 60.f, 170.f);
        CGPathAddLineToPoint(path, NULL, 220.f, 280.f);
        CGPathCloseSubpath(path);
    
        CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
        [anim setDuration:10.f];
        [anim setDelegate:self];
        [anim setPath:path];
        CFRelease(path);
        path = nil;
        [_viewLayer addAnimation:anim forKey:@"position"];

    这里用CGMutablePathRef来产生路径上下文,其实CGMutablePathRef和绘图时的CGContextRef差不多。

    下面设置不再是针对values和keyTimes了,而是设置它的path属性。

    最后不要忘了释放CGMutablePathRef,因为它是CoreFoundation对象没有采用ARC所以要手动管理内存。

  • 相关阅读:
    交通综合改造工程EPC总承包项目
    二三维一体化地理信息平台
    NetCore3.1升级到Net5.0序列化方法过时问题
    windows server2012部署.net core IIS,页面报503,应用程序池自动停止。。。
    NetCore使用NPOI导入Word中的图片信息
    NetCore 使用 iTextSharp 读取 PDF 中的文字信息
    NetCore 在 Docker中文件路径找不到的问题
    Vue中数组list直接push的是对象而不是追加数据的问题
    netcore3.1增加阿里云OSS云存储服务
    Centos中Docker容器中程序访问宿主机Redis和Mysql
  • 原文地址:https://www.cnblogs.com/madpanda/p/4743422.html
Copyright © 2011-2022 走看看