如何制作线条跟踪动画CALayer?

时间:2015-03-27 08:48:15

标签: ios animation core-animation calayer

我有很多动画CALayers,我想在动画时排列一对。

让我们说,有两个动画圈CALayers。我想跟踪CALayers的中心线。我有两种可能的解决方案。

1每当动画添加到圆圈图层时,计算相应的线条动画。

2使用时间计算控制整个动画,灵感来自objc.io。在每个步骤中计算圆圈移动和移动的方式以及线条。

存在问题,在解决方案一中,将会有很差的代码来控制太多的圆形图层,而对于不同的圆形动画,应该有不同的对应。如果有很多圈子和多种动画,事情会更糟,这完全是我的情况。

在解决方案二中,我必须放弃Core Animation并从头开始,这将增加复杂性,将来很难做出一些调整。

有没有更简单,更优雅的方式来做这件事,也许是核心动画背后的一些技巧。非常感谢。

更新: 根据@Duncan C指出的,我正在尝试使用具有相同时间功能的3层。

我根据圆圈创建了线条动画。动画需要是加法的,以便处理多个动画。但动画添加到行CAShaperLayer使整个视图变黑。怎么了?

这是一些代码。 TIA。

- (void)startHorizontalAnimation:(int)duplicateNum {
    // circle animation
    const double distance = 30;
    int totalTime = 600;
    int timeEachDirection = 5;
    double zInterpolation = self.zPosition / duplicateNum;
    double position = distance * 2 * zInterpolation - distance;

    CAKeyframeAnimation *animation = [CAKeyframeAnimation animation];
    animation.keyPath = @"position.x";

    NSMutableArray *valueArr = [[NSMutableArray alloc] initWithObjects:@0, nil];
    for (int i = 0; i < totalTime / (timeEachDirection * 2); ++i) {
        [valueArr addObject:[NSNumber numberWithDouble:position]];
        [valueArr addObject:[NSNumber numberWithDouble:-position]];
    }
    [valueArr addObject:@0];
    animation.values = valueArr;


    animation.additive = YES;
    animation.duration = totalTime;

    NSMutableArray *animationArr = [[NSMutableArray alloc] init];
    for (int i = 0; i < [valueArr count] - 1; ++i) {
        [animationArr addObject:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
    }

    animation.timingFunctions = animationArr;

    animation.delegate = self.delegate;

    [self addAnimation:animation forKey:ANIMI_HORIZONTALD_DISPERSE];

    // line animation
    CAAnimation *startAnimation = [self copyPositionFrom:animation modifyStart:YES onDirectionX:YES];
    CAAnimation *endAnimation = [self copyPositionFrom:animation modifyStart:NO onDirectionX:YES];

    [self.lineFrom addAnimation:startAnimation forKey:nil];
    [self.lineTo addAnimation:endAnimation forKey:nil];

}

// create line animation according to the circle animation, changing the start point or end point on direction x or y.
- (CAAnimation *)copyPositionFrom:(CAKeyframeAnimation *)animation modifyStart:(BOOL)modifyStart onDirectionX:(BOOL)directionX {
    CAKeyframeAnimation *newAnimation = [CAKeyframeAnimation animationWithKeyPath:@"path"];
    newAnimation.additive = animation.additive;
    newAnimation.duration = animation.duration;
    newAnimation.timingFunction = animation.timingFunction;
    newAnimation.delegate = animation.delegate;


    CGPathRef lineCGPath = ((CAShapeLayer *)self.lineFrom).path;
    NSMutableArray *bezierPoints = [NSMutableArray array];
    // MyCGPathApplierFunc is according to http://stackoverflow.com/a/5714872/531966
    CGPathApply(lineCGPath, (__bridge void *)(bezierPoints), MyCGPathApplierFunc);

    __block NSMutableArray *pathArray = [NSMutableArray array];
    [animation.values enumerateObjectsUsingBlock:^(NSNumber *value, NSUInteger idx, BOOL *stop) {

        CGPoint startPoint = [[bezierPoints objectAtIndex:0] CGPointValue];
        CGPoint endPoint = [[bezierPoints objectAtIndex:1] CGPointValue];

        // modify the position additively
        if (modifyStart) {
            if (directionX) {
                startPoint.x += [value floatValue];
            } else {
                startPoint.y += [value floatValue];
            }
        } else {
            if (directionX) {
                endPoint.x += [value floatValue];
            } else {
                endPoint.y += [value floatValue];
            }
        }

        UIBezierPath *linePath = [UIBezierPath bezierPath];
        [linePath moveToPoint:startPoint];
        [linePath addLineToPoint:endPoint];

        [pathArray addObject:linePath];
    }];

    newAnimation.values = pathArray;
    return newAnimation;
}

@interface CircleShapeLayer : CAShapeLayer

@property (nonatomic, weak) CAShapeLayer *lineFrom; // the line goes from the circle
@property (nonatomic, weak) CAShapeLayer *lineTo; // the line goes to the circle

@end

1 个答案:

答案 0 :(得分:1)

我建议用相同的时间创建动画集。

要为2个圆圈和它们之间的直线设置动画,将每个圆形图层的位置属性设置为单独的CABasicAnimation,然后使用第三个CABasicAnimation为该线设置动画(您可以使用CAShapeLayer执行此操作,在其中为动画的起点和终点设置动画。形状图层中的路径。)

或者,您可以为两个圆和连接线使用单个形状图层,同时为路径的所有更改设置动画(让路径包含2个圆和线,并创建一个动画,可以更改控制点3,一次。)