Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subviews Not Positioned Correctly During Animation

I have a simple animation where I'm expanding a new view from the center of the old one, while that one fades out. However, the subviews of this new view (a button and a label) "fly" in from off the lower right hand side of the screen as that new view expands to take up the whole screen. I've tried with and without autolayout turned on, and while the two scenarios give different results, they're both wrong.

The set up is simple, I have two unconnected view controllers in a storyboard, and use the following code to animate the view change:

-(void)switchViews2:(id)sender {
    UIWindow *win = self.view.window;
    YellowController *yellow = [self.storyboard instantiateViewControllerWithIdentifier:@"Yellow"];
    yellow.view.frame = CGRectMake(0, 0, 1, 1);
    yellow.view.center = self.view.center;
    [win addSubview:yellow.view];
    CGRect  frame = self.view.frame;
    [UIView animateWithDuration:5 animations:^{
        yellow.view.frame = frame;
        self.view.alpha = 0;
    }
             completion:^(BOOL finished) {
                 [self.view removeFromSuperview];
                 win.rootViewController = yellow;
         }];
}

The question is, why don't the subviews stay where they're supposed to inside their superview as it animates.

like image 210
rdelmar Avatar asked Dec 15 '12 05:12

rdelmar


2 Answers

To grow a subview into place, particularly when using Autolayout, it is far simpler to animate the transform property instead of the frame. This way, the subview's bounds property does not change, so it does not feel the need to relay out its subviews all the time during the animation.

Add your subview with its final frame, set its transform to be a scaling affine transform of, say, 0.1, then animate it to the identity transform. It will grow out from the center point, with all subviews in the correct position.

like image 93
jrturton Avatar answered Oct 17 '22 00:10

jrturton


The problem was with the layout constraints. If instead of setting the view frame in the animation block, I add constraints between the window and the new view, then call layoutIfNeeded in the animation block it works correctly:

-(void)switchViews2:(id)sender {
    UIWindow *win = self.view.window;
    YellowController *yellow = [self.storyboard instantiateViewControllerWithIdentifier:@"Yellow"];
    [yellow.view setTranslatesAutoresizingMaskIntoConstraints:NO];
    yellow.view.frame = CGRectMake(0, 0, 1, 1);
    yellow.view.center = self.view.center;
    [win addSubview:yellow.view];

    NSLayoutConstraint *con1 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeLeading relatedBy:0 toItem:win attribute:NSLayoutAttributeLeading multiplier:1 constant:0];
    NSLayoutConstraint *con2 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeTop relatedBy:0 toItem:win attribute:NSLayoutAttributeTop multiplier:1 constant:20];
    NSLayoutConstraint *con3 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeTrailing relatedBy:0 toItem:win attribute:NSLayoutAttributeTrailing multiplier:1 constant:0];
    NSLayoutConstraint *con4 = [NSLayoutConstraint constraintWithItem:yellow.view attribute:NSLayoutAttributeBottom relatedBy:0 toItem:win attribute:NSLayoutAttributeBottom multiplier:1 constant:0];

    [win addConstraints:@[con1,con2,con3,con4]];

    [UIView animateWithDuration:1 animations:^{
        [win layoutIfNeeded];
        self.view.alpha = 0;
    }
             completion:^(BOOL finished) {
                 [self.view removeFromSuperview];
                 win.rootViewController = yellow;
         }];
}
like image 28
rdelmar Avatar answered Oct 17 '22 01:10

rdelmar