1

方法 1

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
 [CATransaction begin];
    {
        [CATransaction setAnimationDuration:15];//Dynamic Duration
        [CATransaction setCompletionBlock:^{

        }];

        animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        animation.autoreverses = NO;
        animation.removedOnCompletion = NO;
        animation.fromValue = @0;
        animation.toValue = @1;
        animation.timeOffset = 0;
        animation.fillMode = kCAFillModeForwards;
        [self.pathLayer addAnimation:animation forKey:animationKey];

    }
    [CATransaction commit];

我在我的视图中添加了 CAShapeLayer (pathLayer),我希望它在视图周围以中风效果进行动画处理,上面的代码完成了这项工作,但我的问题是以 3 个相等的比例改变颜色。所以我假设是重复上述代码 3 次,并按相应的顺序更改以下行。

第一次

    animation.fromValue = @0;
    animation.toValue = @(1/3);
    animation.timeOffset = 0;

第 2 名

    animation.fromValue = @(1/3);
    animation.toValue = @(2/3);
    animation.timeOffset = 0;// I don't know how to exactly set this  active local 
time since the duration which is currently 15 is dynamic can be 30 or 10.

第三次

    animation.fromValue = @(2/3);
    animation.toValue = @(3);
    animation.timeOffset = 0;// Active local time- Not sure how and which value to set 

方法 2

而不是使用偏移技术的 3 个事务,让第 1 个事务完成时开始第 2 个事务,当第 2 个事务完成时开始第 3 个事务。但是,当一个动画完成时,开始新动画所花费的时间是可见的。

方法 3

子类 CAShapeLayer

通过做SubClass,drawInContext方法只调用一次,如果添加了一些额外的属性并改变了drawInContext方法,就会重复调用drawInContext方法,这样可以在特定的进度时间后改变图层颜色。但是覆盖 drawInContext 方法并不能达到目的。

有什么建议么 ?我不想单独实现 NSTimer。

4

1 回答 1

8

我不是 100% 清楚你想要什么,但如果目标只是让整个笔画在绘制时改变颜色,但在三个离散的阶段,那么我建议添加以下内容。我在默认的“单一视图应用程序”模板中编写了这些示例。我设置了一个按钮,其动作指向-doStuff:。如果整个笔触颜色发生变化,它可能看起来像这样:

整个笔画变色

为了产生它,代码看起来像:

@implementation MyViewController
{
    CAShapeLayer* mLayer;
}

- (IBAction)doStuff:(id)sender
{
    const NSUInteger numSegments = 3;
    const CFTimeInterval duration = 2;

    [mLayer removeFromSuperlayer];

    mLayer = [[CAShapeLayer alloc] init];
    mLayer.frame = CGRectInset(self.view.bounds, 100, 200);
    mLayer.fillColor = [[UIColor purpleColor] CGColor];
    mLayer.lineWidth = 12.0;
    mLayer.lineCap = kCALineCapSquare;
    mLayer.strokeEnd = 0.0;
    mLayer.path = [[UIBezierPath bezierPathWithRect: mLayer.bounds] CGPath]; // This can be whatever.

    [self.view.layer addSublayer: mLayer];

    [CATransaction begin];
    {
        [CATransaction setAnimationDuration: duration];// Dynamic Duration
        [CATransaction setCompletionBlock:^{ NSLog(@"Done"); }];

        const double portion = 1.0 / ((double)numSegments);
        NSMutableArray* values = [NSMutableArray arrayWithCapacity: numSegments];
        NSMutableArray* times = [NSMutableArray arrayWithCapacity: numSegments + 1];
        for (NSUInteger i = 0; i < numSegments; i++)
        {
            [values addObject: (__bridge id)[[UIColor colorWithHue: i * portion saturation:1 brightness:1 alpha:1] CGColor]];
            [times addObject: @(i * portion)];
        }

        [times addObject: @(1.0)]; // Have to add this, otherwise the last value wont get used.

        {
            CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath: @"strokeColor"];
            animation.keyTimes = times;
            animation.values = values;
            animation.calculationMode = kCAAnimationDiscrete;
            animation.removedOnCompletion = NO;
            animation.timeOffset = 0;
            animation.fillMode = kCAFillModeForwards;
            [mLayer addAnimation: animation forKey: @"strokeColor"];
        }
        {
            CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath: @"strokeEnd"];
            animation.fromValue = @(0);
            animation.toValue = @(1);
            animation.removedOnCompletion = NO;
            animation.timeOffset = 0;
            animation.fillMode = kCAFillModeForwards;
            [mLayer addAnimation: animation forKey: @"strokeEnd"];
        }
    }
    [CATransaction commit];
}

@end

或者,如果目标是让笔画的三个不同部分,都具有不同的颜色,这会稍微复杂一些,但仍然可以使用相同的基本原理来完成。需要注意的一点是,如果没有自定义绘图,您CAShapeLayer的 s 不能有超过一种笔触颜色 (AFAIK),因此您需要将其分解为几个子图层。

下一个示例将一个形状图层放入视图中,然后为笔划的每个部分添加子图层,并设置动画以使其显示为正在绘制一个单一的、多色的笔划,其中每个段都是一种单独的颜色。这大概是它的样子:

输出的动画 GIF

这是代码:

@implementation MyViewController
{
    CAShapeLayer* mLayer;
}

- (IBAction)doStuff:(id)sender
{
    const NSUInteger numSegments = 3;
    const CFTimeInterval duration = 2;

    [mLayer removeFromSuperlayer];

    mLayer = [[CAShapeLayer alloc] init];
    mLayer.frame = CGRectInset(self.view.bounds, 100, 200);
    mLayer.fillColor = [[UIColor purpleColor] CGColor];
    mLayer.lineWidth = 12.0;
    mLayer.lineCap = kCALineCapSquare;
    mLayer.path = [[UIBezierPath bezierPathWithRect: mLayer.bounds] CGPath]; // This can be whatever.

    [self.view.layer addSublayer: mLayer];

    [CATransaction begin];
    {
        [CATransaction setAnimationDuration: duration];//Dynamic Duration
        [CATransaction setCompletionBlock:^{ NSLog(@"Done"); }];

        const double portion = 1.0 / ((double)numSegments);

        for (NSUInteger i = 0; i < numSegments; i++)
        {
            CAShapeLayer* strokePart = [[CAShapeLayer alloc] init];
            strokePart.fillColor = [[UIColor clearColor] CGColor];
            strokePart.frame = mLayer.bounds;
            strokePart.path = mLayer.path;
            strokePart.lineCap = mLayer.lineCap;
            strokePart.lineWidth = mLayer.lineWidth;

            // These could come from an array or whatever, this is just easy...
            strokePart.strokeColor = [[UIColor colorWithHue: i * portion saturation:1 brightness:1 alpha:1] CGColor];
            strokePart.strokeStart = i * portion;
            strokePart.strokeEnd = (i + 1) * portion;

            [mLayer addSublayer: strokePart];

            CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath: @"strokeEnd"];
            NSArray* times = @[ @(0.0), // Note: This works because both the times and the stroke start/end are on scales of 0..1
                                @(strokePart.strokeStart),
                                @(strokePart.strokeEnd),
                                @(1.0) ];
            NSArray* values = @[ @(strokePart.strokeStart),
                                 @(strokePart.strokeStart),
                                 @(strokePart.strokeEnd),
                                 @(strokePart.strokeEnd) ];

            animation.keyTimes = times;
            animation.values = values;
            animation.removedOnCompletion = NO;
            animation.fillMode = kCAFillModeForwards;
            [strokePart addAnimation: animation forKey: @"whatever"];
        }
    }
    [CATransaction commit];
}

@end

我不确定我是否完全理解您的目的,但希望其中之一对您有所帮助。

于 2013-09-06T12:50:32.353 回答