iOS CAKeyFrameAnimation Scaling Flickers at animation end

后端 未结 3 2174
刺人心
刺人心 2021-02-06 12:29

In another test of Key Frame animation I am combining moving a UIImageView (called theImage) along a bezier path and scaling larger it as it moves, resulting in a 2

3条回答
  •  栀梦
    栀梦 (楼主)
    2021-02-06 12:58

    It can be tricky to animate a view's layer using Core Animation. There are several things that make it confusing:

    • Setting an animation on a layer doesn't change the layer's properties. Instead, it changes the properties of a “presentation layer” that replaces the original “model layer” on the screen as long as the animation is applied.

    • Changing a layer's property normally adds an implicit animation to the layer, with the property name as the animation's key. So if you want to explicitly animate a property, you usually want to set the property to its final value, then add an animation whose key is the property name, to override the implicit animation.

    • A view normally disables implicit animations on its layer. It also mucks around with its layer's properties in other somewhat mysterious ways.

    Also, it's confusing that you animate the view's bounds to scale it up, but then switch to a scale transformation at the end.

    I think the easiest way to do what you want is to use the UIView animation methods as much as possible, and only bring in Core Animation for the keyframe animation. You can add the keyframe animation to the view's layer after you've let UIView add its own animation, and your keyframe animation will override the animation added by UIView.

    This worked for me:

    - (IBAction)animate:(id)sender {
        UIImageView* theImage = self.imageView;
        CGFloat scaleFactor = 2;
        NSTimeInterval duration = 1;
    
        UIBezierPath *path = [self animationPathFromStartingPoint:theImage.center];
        CGPoint destination = [path currentPoint];
    
        [UIView animateWithDuration:duration animations:^{
            // UIView will add animations for both of these changes.
            theImage.transform = CGAffineTransformMakeScale(scaleFactor, scaleFactor);
            theImage.center = destination;
    
            // Prepare my own keypath animation for the layer position.
            // The layer position is the same as the view center.
            CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
            positionAnimation.path = path.CGPath;
    
            // Copy properties from UIView's animation.
            CAAnimation *autoAnimation = [theImage.layer animationForKey:@"position"];
            positionAnimation.duration = autoAnimation.duration;
            positionAnimation.fillMode = autoAnimation.fillMode;
    
            // Replace UIView's animation with my animation.
            [theImage.layer addAnimation:positionAnimation forKey:positionAnimation.keyPath];
        }];
    }
    

提交回复
热议问题