How can I replace CGAffineTransform scale and alpha animations using CABasicAnimations and Auto Layout?

4.1k Views Asked by At

As far as I can see, Apple wants us to move away from CGAffineTransform animations and into animations using:

myView.layoutConstraint.constant = someNewValue;

[myView layoutIfNeeded];

for animations that involve a translation of a view.

It also seems we should be now using CABasicAnimation animations for scale and rotation (and sometimes opacity) because it animates the view's layer and not the view and in doing so, plays nicely with auto layout.

I used the following code to apply an opacity and scale animation that worked beautifully:

[UIView animateWithDuration:0.1f animations:^{
//        first animation
self.myMeButton.alpha = 1;
self.myMeButton.transform = CGAffineTransformMakeScale(1.1, 1.1);

} completion:^(BOOL finished) {
    [UIView animateWithDuration:0.2f animations:^{
        //        second animation
        self.myButton.transform = CGAffineTransformMakeScale(1, 1);
    }];
}];

Of course auto layout plays havoc with the scale animation and so I am trying to find an alternative way to do it. So far, I have come up with this:

    [CATransaction begin]; {
    [CATransaction setCompletionBlock:^{
        //            code for when animation completes
        self.pickMeButton.alpha = 1;

        CABasicAnimation *scaleDown = [CABasicAnimation animationWithKeyPath:@"scale"];
        scaleDown.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
        scaleDown.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
        scaleDown.duration = 0.1;

        [self.myButton.layer addAnimation:scaleDown forKey:nil];

    }];
    //  describe animations:
    CABasicAnimation* scaleUp = [CABasicAnimation animationWithKeyPath:@"scale"];
    scaleUp.autoreverses = NO;
    scaleUp.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
    scaleUp.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];

    CABasicAnimation *fadeAnim = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeAnim.fromValue=[NSNumber numberWithDouble:0.0];
    fadeAnim.toValue=[NSNumber numberWithDouble:1.0];

    // Customization for all animations:
    CAAnimationGroup *group = [CAAnimationGroup animation];
    group.duration = 0.2f;
    group.repeatCount = 1;
    group.autoreverses = NO;
    group.animations = @[scaleUp, fadeAnim];

    // add animations to the view's layer:
    [self.myButton.layer addAnimation:group forKey:@"allMyAnimations"];


} [CATransaction commit];

As you can see the code almost 3 times as long as before and the animation on the device is noticeably less 'smooth' than it was previously.

Is there any way to do this better?

Thanks in advance for your response.

EDIT: This seems to have done the trick in that the animations are smooth, but I still feel like the code for this could be a lot more succinct.

[UIView animateWithDuration:0.2f animations:^{

    self.pickMeButton.alpha = 1;

    CABasicAnimation* scaleUp = [CABasicAnimation animationWithKeyPath:@"transform"];
    scaleUp.duration = 0.2;
    scaleUp.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.1, 0.1, 1)];
    scaleUp.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1)];
    [self.pickMeButton.layer addAnimation:scaleUp forKey:nil];

}completion:^(BOOL finished) {

    CABasicAnimation* scaleDown = [CABasicAnimation animationWithKeyPath:@"transform"];
    scaleDown.duration = 0.1;
    scaleDown.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.2, 1.2, 1)];
    scaleDown.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1, 1, 1)];
    [self.pickMeButton.layer addAnimation:scaleDown forKey:nil];

}];
1

There are 1 best solutions below

2
On

I don't know why you want to do it with CABasicAnimation for scale. You can do it like you mention at the top of your question. Set a new value for the view's width and height constraint constant values and then use [myView layoutIfNeeded] inside animateWithDuration. If the view doesn't have height and width constraints, but has constants to the top and bottom and/or left and right edges of the superview, change those values instead.