質問

I have a custom CALayer with an animatable property called progress. The basic code is:

@implementation AnimatedPieChartLayer

@dynamic progress;

+ (BOOL)needsDisplayForKey:(NSString *)key {
    return [key isEqualToString: @"progress"] || [super needsDisplayForKey: key];
}

- (id <CAAction>)actionForKey:(NSString *)key {
    if ([self presentationLayer] != nil) {
        if ([key isEqualToString: @"progress"]) {
            CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath: key];
            [anim setFromValue: [[self presentationLayer] valueForKey: key]];
            [anim setDuration: 0.75f];
            return anim;
        }
    }
    return [super actionForKey: key];
}

- (void)drawInContext:(CGContextRef)context {
  // do stuff
}

@end

In the view controller I do this, to try and get my animation to start from the beginning every time:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear: animated];

    [pieChart setProgress: 0.0];
}

This all works perfectly. I put the layer on a view, the view in a view controller, and it all works as expected.

The complication is that my view controller is inside a UIScrollView. This presents a situation where the user could swipe away from my view controller before the CALayer animation completes. If they swipe back quickly, the CALayer animation does something weird. It reverses. It's like the animation is trying to go back to the beginning. Once it gets there it starts over, and animates the way it is supposed to.

So the question is, how can I prevent this. I want the animation to start from the beginning every time the view is displayed – regardless of what happened last time.

Any suggestions?

UPDATE

Here's a visual example of the problem:

Working:

enter image description here

Failing:

enter image description here

役に立ちましたか?

解決

In the setup you have there, you have an implicit animation for the key "progress" so that whenever the progress property of the layer changes, it animates. This works both when the value increases and when it decreases (as seen in your second image).

To restore the layer to the default 0 progress state without an animation, you can wrap the property change in a CATransaction where all actions are disabled. This will disable the implicit animation so that you can start over from 0 progress.

[CATransaction begin];
[CATransaction setDisableActions:YES]; // all animations are disabled ...
[pieChart setProgress: 0.0];
[CATransaction commit]; // ... until this line

他のヒント

Probably too simple a suggestion to merit an 'answer,' but I would suggest canceling the animation. Looks like you could rewrite this code pretty easily so that the progress updates were checking some complete flag and then when the view get hidden, kill it. This thread has some good ideas on it.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top