How to use UIBezierPath with CoreAnimation?

2019-02-19 12:34发布

问题:

I am using this code to remove animate my UIView to the delete button on delete button press. Here's the code :

UIBezierPath *movePath = [UIBezierPath bezierPath];
            [movePath moveToPoint:icon.center];
            [movePath addQuadCurveToPoint:senderView.center
                             controlPoint:CGPointMake(senderView.center.x, icon.center.y)];

            CAKeyframeAnimation *moveAnim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
            moveAnim.path = movePath.CGPath;
            moveAnim.removedOnCompletion = YES;

            CABasicAnimation *scaleAnim = [CABasicAnimation animationWithKeyPath:@"transform"];
            scaleAnim.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
            scaleAnim.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1.0)];
            scaleAnim.removedOnCompletion = YES;

            CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:@"alpha"];
            opacityAnim.fromValue = [NSNumber numberWithFloat:1.0];
            opacityAnim.toValue = [NSNumber numberWithFloat:0.1];
            opacityAnim.removedOnCompletion = YES;

            CAAnimationGroup *animGroup = [CAAnimationGroup animation];
            animGroup.animations = [NSArray arrayWithObjects:moveAnim, scaleAnim, opacityAnim, nil];
            animGroup.duration = 2.0;
            [icon.layer addAnimation:animGroup forKey:nil];

And this actually animating the UIView to the delete button but after it's showing up in the same place again.

回答1:

Animations apply to the presentation layer, not the model layer. You need to apply your changes to both. That's a fancy way of saying that when you do animate something, you also need to set it directly.

        ...
        [icon.layer setPosition:CGPointMake(senderView.center.x, icon.center.y)];
        [icon.layer setTransform:CATransform3DMakeScale(0.1, 0.1, 1.0)]];
        [icon.layer setAlpha:0.1];

(Note that you may want to animate the view's center here rather than the layer's position.)

Chapter 7 of iOS 5 Programming Pushing the Limits has pages and pages on this if you want all the gory details. Here's the section on removedOnCompletion:

Sometimes you see people recommend setting removedOnCompletion to NO and fillMode to kCAFillModeBoth. This is not a good solution. It essentially makes the animation go on forever, which means the model layer is never updated. If you ask for the property’s value, you continue to see the model value, not what you see on the screen. If you try to implicitly animate the property afterward, it won’t work correctly because the CAAnimation is still running. If you ever remove the animation by replacing it with another with the same name, calling removeAnimationForKey: or removeAllAnimations, the old value snaps back. On top of all of that, it wastes memory.



回答2:

Set each animation’s removedOnCompletion to NO and its fillMode to kCAFillModeForwards.



回答3:

Try changing the opacity animation to:

CABasicAnimation *opacityAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];

and then set the animation group's removeOnCompletion to NO and its fillMode to kCAFillModeForwards like Noah Witherspoon suggested.