ioscore-animationcatransition

iOS - CATransition issue: showing end image at start


In my UIViewController I create CALayer with image1.

CALayer *imageLayer = [CALayer layer];
[imageLayer setBounds:CGRectMake(0.0, 0.0, 241.0, 430.0)];
[imageLayer setPosition:CGPointMake(160.0, 60.0)];
[imageLayer setAnchorPoint:CGPointMake(0.5, 0.0)];
[imageLayer setContents:(id)[UIImage imageNamed:@"image1.png".CGImage];
[imageLayer setContentsGravity:kCAGravityResizeAspect];
[self.view.layer addSublayer:imageLayer];

Later in UIViewController I want to change image by pushing it using CATransition.

CATransition *t = [CATransition animation];
t.beginTime = [self.view.layer convertTime:CACurrentMediaTime() + 6.5 fromLayer:nil];
t.type = kCATransitionPush;
t.subtype = kCATransitionFromRight;
[imageLayer setContents:(id)[UIImage imageNamed:@"image2.png"].CGImage];    
[imageLayer addAnimation:t forKey:nil];

When running the code I get image2 from the beginning, transition works though by pushing itself after 6.5 seconds. Where's the image1? What's wrong?

Correct answer: Thanks both Jacky Boy and Tiago Almeida. I corrected the code removing the line

t.beginTime = [self.view.layer convertTime:CACurrentMediaTime() + 6.5 fromLayer:nil];

and adding 'dispatch_after'.

Now it works:

CATransition *t = [CATransition animation];
t.type = kCATransitionPush;
t.subtype = kCATransitionFromRight;
[imageLayer setContents:(id)[UIImage imageNamed:@"image2.png"].CGImage];    
[imageLayer addAnimation:t forKey:nil];
[CATransaction begin];
NSTimeInterval delayInSeconds = 6.5;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [imageLayer setContents:(id)[UIImage imageNamed:@"image2.png"].CGImage];
    [imageLayer addAnimation:t forKey:nil];
});
[CATransaction commit];

Thanks again, guys!


Solution

  • Remove the following line:

    t.beginTime = [self.view.layer convertTime:CACurrentMediaTime() + 1.5 fromLayer:nil];
    

    This is what delaying the animation, so the layer is setting the new content, and only after the layer is animated. If you want to specify the duration of the animation:

    [CATransaction begin];
    [CATransaction setAnimationDuration:1.0];
    
    CATransition *t = [CATransition animation];
    t.type = kCATransitionPush;
    t.subtype = kCATransitionFromRight;
    [_layer setContents:(id)[UIImage imageNamed:@"image2.jpg"].CGImage];
    [_layer addAnimation:t forKey:nil];
    
    
    [CATransaction commit];
    

    Or a smaller version:

    CATransition *t = [CATransition animation];
    t.type = kCATransitionPush;
    [t setDuration:2.5];
    t.subtype = kCATransitionFromRight;
    [_layer setContents:(id)[UIImage imageNamed:@"image2.jpg"].CGImage];
    [_layer addAnimation:t forKey:nil];
    

    I would prefer this:

    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionPush;
    transition.duration = .25f;
    transition.subtype = kCATransitionFromRight;
    
    _layer.actions = @{@"contents": transition};
    

    And when you want to change the content:

    [_layer setContents:(id)[UIImage imageNamed:@"image2.jpg"].CGImage];