动画时更改CALayer颜色 [英] Change CALayer color while animating

查看:128
本文介绍了动画时更改CALayer颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

APPROACH 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次并按相应顺序更改以下行。

I have added CAShapeLayer (pathLayer) in my view and I want it to animate around the view with stroke effect, the code above does the job but my problem is to change color in 3 equal proportions. So what I am assuming is to repeat the above code 3 times and change the following lines in respective order.

for 1st

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

第二次

    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 

APPROACH 2

不是使用抵消技术处理3个事务,而是在第一个完成时开始第二个事务,在第二个完成时开始第三个事务。但是,完成一个新动作后,开始播放新动画所花费的时间比例是可见的。

Instead of 3 transactions with offset technique lets start 2nd transaction when 1st completes and 3rd when 2nd. But the fraction of time that is taken to start the new animation when one is completed a lag/jerk is visible.

APPROACH 3

SubClass CAShapeLayer

SubClass CAShapeLayer

通过执行SubClass,drawInContext方法仅被调用一次,并且如果添加了一些额外的属性,更改后将重复调用drawInContext方法,这样可以在特定的时间段后更改图层颜色。
但是,重写drawInContext方法并不能达到目的。

By doing SubClass, the drawInContext method is called only once, and if some extra property is added and it is changed the drawInContext method is called repeatedly and this way the layer color can be changed after specific progress period of time. But overriding the drawInContext method doesn't serve the purpose.

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

Any Suggestions ? I don't want to implement NSTimer separately.

推荐答案

我不清楚您要在这里做什么,但如果不是,目标只是使整个笔画在绘制时改变颜色,但是在三个独立的阶段中,我建议添加以下内容。我在默认的单视图应用程序模板中准备了这些示例。我已经设置了一个按钮,其操作指向 -doStuff:。如果整个笔触颜色发生变化,则可能看起来像这样:

I'm not 100% clear on what you want here, but if the goal is just for the whole stroke to change color as it draws, but in three discrete stages, then I would propose adding the following. I cooked up these examples in a default "Single View Application" template. I've got a button set up with its action pointing at -doStuff:. If the whole stroke color were to change, it might look something like this:

要生成该代码,代码应类似于:

To produce that, the code looked like:

@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 不能具有多个笔触颜色(AFAIK),因此您需要将其分解为几个子层。

Alternately, if the goal is to have three different segments of the stroke, all with different colors, that's a little more complicated, but can still be done with the same basic principals. One thing to note is that, without custom drawing, your CAShapeLayers can't have more than one stroke color (AFAIK), so you'll need to break this up into several sublayers.

下一个示例在视图中放置一个形状层,然后为笔触的每个部分添加了子层,并设置了动画,使其看起来像一个单一的,多个的-绘制彩色笔触,其中每个段都是单独的颜色。大致如下所示:

This next example puts a shape layer into the view and then adds the sublayers for each part of the stroke and sets up the animation such that it appears theres a single, multi-color stroke being drawn, where each segment is a separate color. Here's roughly what it looked like:

这是代码:

@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

我不确定已经完全了解您要做什么,但希望其中之一会有所帮助。

I'm not sure I've exactly understood what you were going for, but hopefully one of these is helpful.

这篇关于动画时更改CALayer颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆