Brian Tracy
Brian Tracy

Reputation: 6831

Stop the call of -removeAllAnimaitions

Currently on the iOS platform, when the home button is pressed, -removeAllAnimations is sent to each view's layer property.

I desperately need to stop this behavior!

I am currently using a CABasicAnimation that animates the drawing of a circle to act as a timer.

Here is a gif of the process. The timer starts and the animation begins smoothly (pardon the poor fps). Once the home button is pressed and I come back to the app, the animation immediately finishes.

I am using the - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag method to detect when the timer is stopped. This is all working out really well, until I press the home button.

Pressing the home button immediately completes the animation and prematurely completes the timer.

Is there any way to stop this behavior such as a method on UIViewController or some property I can set in the .plist of my project?

Here is the source for my first statement. CABasicAnimation disappear when home button is pushed

Here are my current attempts to solve the problem.

  1. Subclass CALayer to override -removeAllAnimations in hope of preventing the stopping of the animation.
  2. Performed method swizzling in the +load method in an extension on the CALayer class that swizzles -removeAllAnimations to some bogus method. I have determined that the bogus method is being called, yet the same behavior is still being experienced.

Upvotes: 4

Views: 209

Answers (2)

Brian Tracy
Brian Tracy

Reputation: 6831

First off, I want to thank @KudoCC for the response.

While the given solution might work, I have found an easier way with the -[CAAnimation removedOnCompletion] property.

CAAnimation * anim = ...;
anim.removedOnCompletion = NO;
// anim will now continue after home button press

This solution seems to override the default calls of -[CALayer removeAllAnimations] issued by the OS when the home button is pressed.

Upvotes: 2

KudoCC
KudoCC

Reputation: 6952

I create an example to animate the position of a CALayer using CABasicAnimation.

The idea is to store some context of the animation when app goes to background and restore the animation when app goes back.

@interface ViewController ()
{
    BOOL animationStoped ;
    CFTimeInterval time ;
    CGPoint position ;
}

@property (nonatomic, strong) UIView *viewAnimate ;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    _viewAnimate = [[UIView alloc] initWithFrame:CGRectMake(0.0, 100.0, 100.0, 100.0)] ;
    _viewAnimate.backgroundColor = [UIColor redColor] ;
    [self.view addSubview:_viewAnimate] ;
    CABasicAnimation *animation = [self animation] ;
    [_viewAnimate.layer addAnimation:animation forKey:@"animation.position"] ;
    _viewAnimate.layer.position = CGPointMake(250.0, 350.0) ;
    time = [_viewAnimate.layer convertTime:CACurrentMediaTime() fromLayer:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleEnterBackgroundNotification:)
                                                 name:UIApplicationDidEnterBackgroundNotification
                                               object:nil] ;
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleDidBecomeActiveNotification:)
                                                 name:UIApplicationDidBecomeActiveNotification
                                               object:nil] ;

}

- (CABasicAnimation *)animation
{
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"] ;
    animation.fromValue = [NSValue valueWithCGPoint:CGPointMake(50.0, 50.0)] ;
    animation.toValue = [NSValue valueWithCGPoint:CGPointMake(250.0, 350.0)] ;
    animation.duration = 5.0 ;
    animation.delegate = self ;
    return animation ;
}

- (void)handleEnterBackgroundNotification:(id)nty
{
    CAAnimation *aa = [_viewAnimate.layer animationForKey:@"animation.position"] ;
    animationStoped = aa != nil ;
    if (animationStoped) {
        CALayer *presentationLayer = _viewAnimate.layer.presentationLayer ;
        position = presentationLayer.position ;
        CFTimeInterval now = [_viewAnimate.layer convertTime:CACurrentMediaTime() fromLayer:nil];
        time = now - time ;
    }
}

- (void)handleDidBecomeActiveNotification:(id)nty
{
    if (animationStoped) {
        CABasicAnimation *animation = [self animation] ;
        animation.fromValue = [NSValue valueWithCGPoint:position] ;
        animation.duration -= time ;
        [_viewAnimate.layer addAnimation:animation forKey:@"animation.position"] ;
    }
}

Upvotes: 2

Related Questions