iOS Core Animation Advanced Techniques-图层时间

上八章节:

  1. 图层树
  2. 图层的寄宿图
  3. 图层几何学
  4. 图层视觉效果
  5. 图层变换
  6. 专用图层
  7. 隐式动画
  8. 显式动画

这篇随笔主要介绍有关图层时间。

  • CAMediaTiming协议:
    • 定义了在一段动画内用来控制逝去时间的属性的集合
    • CALayer和CAAnimation都实现了这个协议,所以时间可以被任意基于一个图层或者一段动画的类控制
    • 属性:
      • duration:
        • 指定动画的一次迭代的时间(默认0,代表默认时间0.25)
      • repeatCount:
        • 动画重复的迭代次数(默认0,代表默认次数1)
        • /*
        • 完整的动画时长=duration*repeatCount
        • */
      • 示范例子:
        • //add the ship
        • self.shipLayer = [CALayer layer];
        • self.shipLayer.frame = CGRectMake(0, 0, 128, 128);
        • self.shipLayer.position = CGPointMake(150, 150);
        • self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
        • [self.containerView.layer addSublayer:self.shipLayer];
        • CFTimeInterval duration = 3.0;
        • float repeatCount = 10.0;
        • CABasicAnimation *animation = [CABasicAnimation animation];
        • animation.keyPath = @"transform.rotation";
        • animation.duration = duration;
        • animation.repeatCount = repeatCount;
        • animation.byValue = @(M_PI * 2);
        • [self.shipLayer addAnimation:animation forKey:@"rotateAnimation"];

 

      • repeatDuration:
        • 让动画重复一个指定的时间
      • autoreverses:
        • 是否在每次间隔交替循环过程中自动回放
      • /*
      • repeatCount和repeatDuration可能会相互冲突,所以你只要对其中一个指定非零值
      • */
      • 示范例子:
        • //add the door
        • CALayer *doorLayer = [CALayer layer];
        • doorLayer.frame = CGRectMake(0, 0, 128, 256);
        • doorLayer.position = CGPointMake(150 - 64, 150);
        • doorLayer.anchorPoint = CGPointMake(0, 0.5);
        • doorLayer.contents = (__bridge id)[UIImage imageNamed: @"Door.png"].CGImage;
        • [self.containerView.layer addSublayer:doorLayer];
        • //apply perspective transform
        • CATransform3D perspective = CATransform3DIdentity;
        • perspective.m34 = -1.0 / 500.0;
        • self.containerView.layer.sublayerTransform = perspective;
        • //apply swinging animation
        • CABasicAnimation *animation = [CABasicAnimation animation];
        • animation.keyPath = @"transform.rotation.y";
        • animation.toValue = @(-M_PI_2);
        • animation.duration = 2.0;
        • animation.repeatDuration = INFINITY;
        • animation.autoreverses = YES;
        • [doorLayer addAnimation:animation forKey:nil];
      • beginTime:
        • 指定了动画开始之前的的延迟时间(默认0,动画马上执行)
      • speed:
        • 一个时间的倍数,默认1.0
        • 减少它会减慢图层/动画的时间;
        • 增加它会加快速度
        • timeOffset:
        • 让动画快进到某一点
        • 例如:
        • 对于一个持续1秒的动画来说,设置timeOffset为0.5意味着动画将从一半的地方开始。
        • 不受speed的影响
        • 示范例子:
          • //create a path
          • self.bezierPath = [[UIBezierPath alloc] init];
          • [self.bezierPath moveToPoint:CGPointMake(0, 150)];
          • [self.bezierPath addCurveToPoint:CGPointMake(300, 150) controlPoint1:CGPointMake(75, 0) controlPoint2:CGPointMake(225, 300)];
          • //draw the path using a CAShapeLayer
          • CAShapeLayer *pathLayer = [CAShapeLayer layer];
          • pathLayer.path = self.bezierPath.CGPath;
          • pathLayer.fillColor = [UIColor clearColor].CGColor;
          • pathLayer.strokeColor = [UIColor redColor].CGColor;
          • pathLayer.lineWidth = 3.0f;
          • [self.containerView.layer addSublayer:pathLayer];
          • //add the ship
          • self.shipLayer = [CALayer layer];
          • self.shipLayer.frame = CGRectMake(0, 0, 64, 64);
          • self.shipLayer.position = CGPointMake(0, 150);
          • self.shipLayer.contents = (__bridge id)[UIImage imageNamed: @"Ship.png"].CGImage;
          • [self.containerView.layer addSublayer:self.shipLayer];
          • //create the keyframe animation
          • CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
          • animation.keyPath = @"position";
          • animation.timeOffset = self.timeOffsetSlider.value;
          • animation.speed = self.speedSlider.value;
          • animation.duration = 1.0;
          • animation.path = self.bezierPath.CGPath;
          • animation.rotationMode = kCAAnimationRotateAuto;
          • animation.removedOnCompletion = NO;//在动画结束的时候仍然保持之前的状态
          • [self.shipLayer addAnimation:animation forKey:@"slide"];
      • fillMode:
        • 避免在动画结束的时候急速返回,当用它来解决这个问题的时候,
        • 需要把removeOnCompletion设置为NO
        • 另外需要给动画添加一个非空的键,于是可以在不需要动画的时候把它从图层上移除。
        • 一个NSString类型
        • 接受如下四种常量:
          • kCAFillModeForwards
            • 向前
          • kCAFillModeBackwards
            • 向后
          • kCAFillModeBoth
            • 向前又向后去填充动画状态
          • kCAFillModeRemoved(默认值)
        • 当动画不再播放的时候就显示图层模型指定的值
  • 层级关系时间:
    • 每个动画和图层在时间上都有它自己的层级概念,相对于它的父亲来测量(类似与子图层的坐标体系)
    • 对图层调整时间将会影响到它本身和子图层的动画,但不会影响到父图层。
      • /*
      • beginTime,timeOffset和speed属性将会影响到子动画
      • 但是对CALayer或者CAGroupAnimation调整duration和repeatCount/repeatDuration属性并不会影响到子动画
      • */
    • 为了同步不同图层之间有不同的speed,timeOffset和beginTime的动画
    • CALayer同样也提供了方法来转换不同图层之间的本地时间。如下:
      • - (CFTimeInterval)convertTime:(CFTimeInterval)t fromLayer:(CALayer *)l;
      • - (CFTimeInterval)convertTime:(CFTimeInterval)t toLayer:(CALayer *)l;
  • 暂停,倒回和快进:
    • 如果移除图层正在进行的动画,图层将会急速返回动画之前的状态。
    • 给图层添加一个CAAnimation实际上是给动画对象做了一个不可改变的拷贝,所以对原始动画对象属性的改变对真实的动画并没有作用。
    • 直接用-animationForKey:来检索图层正在进行的动画可以返回正确的动画对象,但是修改它的属性将会抛出异常。
    • 如果在动画移除之前拷贝呈现图层到模型图层,动画将会看起来暂停在那里。但是不好的地方在于之后就不能再恢复动画了。
    • 解决方案:
      • 通过属性speed实现暂停,倒回,快进:
        • 暂停:
          • 把图层的speed设置成0,它会暂停任何添加到图层上的动画
        • 倒回:
          • 设置成一个负值将会倒回动画。
        • 快进:
          • 设置speed大于1.0将会快进
        • /*
        • 通过增加主窗口图层的speed,可以暂停整个应用程序的动画。
        • */
  • 手动动画:
    • 通过timeOffset手动控制动画进程
    • 再通过speed设置为0,禁用动画的自动播放
    • 再使用timeOffset来回显示动画序列
    • 示范例子:
      • //add the door
      • self.doorLayer = [CALayer layer];
      • self.doorLayer.frame = CGRectMake(0, 0, 128, 256);
      • self.doorLayer.position = CGPointMake(150 - 64, 150);
      • self.doorLayer.anchorPoint = CGPointMake(0, 0.5);
      • self.doorLayer.contents = (__bridge id)[UIImage imageNamed:@"Door.png"].CGImage;
      • [self.containerView.layer addSublayer:self.doorLayer];
      • //apply perspective transform
      • CATransform3D perspective = CATransform3DIdentity;
      • perspective.m34 = -1.0 / 500.0;
      • self.containerView.layer.sublayerTransform = perspective;
      • //add pan gesture recognizer to handle swipes
      • UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] init];
      • [pan addTarget:self action:@selector(pan:)];
      • [self.view addGestureRecognizer:pan];
      • //pause all layer animations
      • self.doorLayer.speed = 0.0;
      • //apply swinging animation (which won't play because layer is paused)
      • CABasicAnimation *animation = [CABasicAnimation animation];
      • animation.keyPath = @"transform.rotation.y";
      • animation.toValue = @(-M_PI_2);
      • animation.duration = 1.0;
      • [self.doorLayer addAnimation:animation forKey:nil];
      • - (void)pan:(UIPanGestureRecognizer *)pan{
      • //get horizontal component of pan gesture
      • CGFloat x = [pan translationInView:self.view].x;
      • //convert from points to animation duration //using a reasonable scale factor
      • x /= 200.0f;
      • //update timeOffset and clamp result
      • CFTimeInterval timeOffset = self.doorLayer.timeOffset;
      • timeOffset = MIN(0.999, MAX(0.0, timeOffset - x));
      • self.doorLayer.timeOffset = timeOffset;
      • //reset pan gesture
      • [pan setTranslation:CGPointZero inView:self.view];//重置手势
      • }
posted @ 2016-03-12 22:24  Jk_Chan  阅读(240)  评论(0编辑  收藏  举报