0
votes

I've dig through all the internet sites and haven't found solution. My problem is changing CALayer position with CAKeyframeAnimation. I cannot set up final value of layer's position after animation ends (position resets to it's final value). All of the tutorials, examples and answers contains two information: sets final value to model layer before or after adding animation to layer (in other words immediately), but this is not working as expected. Instead of this I must set final value in CATransaction's completion block, but this results in flicker (layer's position reset to initial value and then sets to final value). Here's my code with some comments.

CGPoint originalPosition =    self.mainContainerView.contentContainerView.layer.position;
    [CATransaction lock];
    [CATransaction begin];
    [CATransaction setCompletionBlock:^{
        //Setting final value works here, but layer resets to initial position and then this line is invoked (ugly flicker effect)
        self.mainContainerView.contentContainerView.layer.position = CGPointMake(originalPosition.x, originalPosition.y + _menuOffset);
        _menuViewState = MenuViewStateOpened;
        [self.mainContainerView.contentContainerView.layer removeAllAnimations];
    }];

    _menuOffset = self.mainContainerView.menuContainerView.frame.size.height;
    CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    keyframeAnimation.path = [self getBounceCGPath];
    keyframeAnimation.keyTimes = @[@0, @(2 / 6.0), @(3 / 6.0), @(4 / 6.0), @(5 / 6.0), @1];
    keyframeAnimation.duration = 0.4;
    //Without this two lines ugly flicker appears (final value is not set, so this is workaround)
    keyframeAnimation.fillMode = kCAFillModeForwards;
    keyframeAnimation.removedOnCompletion = NO;
    //-------------------------------------------

    //This should prevent for setting final value before animation starts
    [CATransaction setDisableActions:YES];

    //Setting final value (for unknown reason this is not working, moving this line after 'addAnimation' method does not work either)
    self.mainContainerView.contentContainerView.layer.position = CGPointMake(originalPosition.x, originalPosition.y + _menuOffset);
    [self.mainContainerView.contentContainerView.layer addAnimation:keyframeAnimation
                                                             forKey:@"reveal"];
    [CATransaction commit];
    [CATransaction unlock];
1

1 Answers

1
votes

I have always set the new value before adding the animation and it works fine. So don't bother with a completion block just do:

_menuOffset = self.mainContainerView.menuContainerView.frame.size.height;
self.mainContainerView.contentContainerView.layer.position = CGPointMake(originalPosition.x, originalPosition.y + _menuOffset);

CAKeyframeAnimation *keyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
keyframeAnimation.path = [self getBounceCGPath];
keyframeAnimation.keyTimes = @[@0, @(2 / 6.0), @(3 / 6.0), @(4 / 6.0), @(5 / 6.0), @1];
keyframeAnimation.duration = 0.4;
keyframeAnimation.removedOnCompletion = NO;
[self.mainContainerView.contentContainerView.layer addAnimation:keyframeAnimation forKey:@"reveal"];

Setting the new animatable value of the layer should be the first thing you do unless you want it to pop back.