如何将不同图层的核心动画链接到一个接一个?

时间:2012-02-03 01:58:26

标签: ios core-animation calayer

我有一个启用了分页的scrollView和N个页面,它们是UIViews作为scrollView的子视图。

我正在尝试执行以下操作:

用户滚动到页码n。 此时,7个CALayers之前添加到页码n (也就是说,页面[[scrollView subviews] objectAtIndex:n-1] .layer subLayers])一个接一个地淡入。

但是我无法弄清楚如何让CALayers顺序淡出。到目前为止,我已经尝试过我的控制器委托方法中的以下3种方法: (假设我有一个数组到层,并且在创建时它们的不透明度设置为0)

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
  if(pageNumber == (n-1))
  {
    int timeOffset = 0;

    [CATransaction begin];
    for(CALayer *layer in layerArray)
    {
      CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
      a.duration = 6;
      a.beginTime = timeOffset++;
      a.fromValue = [NSNumber numberWithFloat:0.];
      a.toValue = [NSNumber numberWithFloat:1.];

      [layer addAnimation:a forKey:nil];
    }
    [CATransaction commit];
  }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
  if(pageNumber == (n-1))
  {
    int timeOffset = 0;

    [CATransaction begin];
    for(CALayer *layer in layerArray)
    {
      CABasicAnimation *a = [CABasicAnimation animation];
      a.duration = 6;
      a.beginTime = timeOffset++;
      [layer addAnimation:a forKey:@"opacity"];
      [layer setOpacity:1];
    }
    [CATransaction commit];
  }
}


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
  int pageNumber = floor(self.scrollView.contentOffset.x / self.scrollView.frame.size.width);
  if(pageNumber == (n-1))
  {
    int timeOffset = 0;


    for(CALayer *layer in layerArray)
    {
      [CATransaction begin];
      CABasicAnimation *a = [CABasicAnimation animation];
      a.duration = 6;
      a.beginTime = timeOffset++;
      [layer addAnimation:a forKey:@"opacity"];
      [layer setOpacity:1];
    }

    for(CALayer *layer in layerArray)
      [CATransaction commit];
  }
}

但似乎都不起作用。当用户滚动到右侧页面时,所有图层立即变为可见,没有太多淡入淡出,并且绝对不按任何顺序排列。

有什么想法吗?

3 个答案:

答案 0 :(得分:18)

实际上,关键是根据参考帧获取当前时间并将任何时间偏移添加到当前时间。这也适用于未分组的动画。

例如,这段代码中的某些内容会导致n个图层(假设存储在某个数组中)依次逐渐淡入,每个图层占用.8秒。

  CGFloat timeOffset = 0;
  [CATransaction begin];
  for(CALayer *layer in layers)
  {
    CABasicAnimation *a = [CABasicAnimation animationWithKeyPath:@"opacity"];
    a.fromValue = [NSNumber numberWithFloat:0.];
    a.toValue = [NSNumber numberWithFloat:1.];
    a.fillMode = kCAFillModeForwards;
    a.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] + timeOffset;
    a.duration = .8;
    a.removedOnCompletion = NO;
    [layer addAnimation:a forKey:nil];

    timeOffset += .8;
  }
  [CATransaction commit];

在上述情况下,引用框架只是调用发生时的当前时间。

答案 1 :(得分:5)

如果beginTimeCAAnimation的一部分,则CAAnimation的{​​{1}}属性似乎才有效。我认为您还需要将CAAnimationGroup的{​​{1}}属性设置为足以持续到最终动画完成为止。

https://stackoverflow.com/a/563486/77567

答案 2 :(得分:0)

在Swift 3中 (layers是CALayer或CAShapeLayer的数组)

var timeOffset:Double = 0
for layer in layers {
    let a = CABasicAnimation(keyPath: "path"
    a.fromValue = layer.ovalPathSmall.cgPath
    a.toValue = layer.ovalPathLarge.cgPath
    a.fillMode = kCAFillModeForwards
    a.beginTime = CACurrentMediaTime() + timeOffset
    a.duration = 0.3
    a.isRemovedOnCompletion = false
    layer.add(a, forKey: nil)

    timeOffset += 0.3
}

如果你想知道是什么的ovalPathSmall和ovalPathLarge:

ovalPathSmall = UIBezierPath(arcCenter: position, radius: smallRadius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
ovalPathLarge = UIBezierPath(arcCenter: position, radius: largeRadius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)