4
votes

It's kind the weird I'm facing right now, I know that adding constraints in an AutoLayout IB is simple. But I really couldn't figure-out why my simple constraints are not working when I'm resizing (ZoomIn Animation) a UIView.

The View I'm targeting to zoomIn works fine, but the subviews within it is not being positioned well. It seems that the constraints are not working.

From this setup, where in the Yellow Boxes are UIViews and the Green Boxes are UIImageViews. When I tapped on a Yellow Box, it should zoomIn, as what is shown on the photo below it.

enter image description here

These are the constraints:
enter image description here

This should be the expected resulting upon zoomIn AnimationBut I got no luck, The yellow box zoomIn but the Green Box is let on its old position and did not changed size.

I put a leading, trailing, topSpace, and bottomSpace from Yellow Box to Green Box already. My code for resizing the yellow box is:

- (void) resizeViewWithZoomInAnimation: (UIView*)view duration:(float)secs option:(UIViewAnimationOptions) option {

//sets the new width and height of deal's view
float newWidth = view.superview.frame.size.width - 20;
float newHeight = view.superview.frame.size.height - 20;

[UIView animateWithDuration:secs delay:0.0 options:option
                 animations: ^{

                     switch ([view tag]) {
                         case 1:
                             [view setFrame:CGRectMake(view.frame.origin.x, view.frame.origin.y, newWidth, newHeight)];
                             break;
                         case 2:
                             [view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMinY(view.frame), -newWidth , newHeight)];
                             break;
                         case 3:
                             [view setFrame:CGRectMake(CGRectGetMinX(view.frame),CGRectGetMaxY(view.frame), newWidth , -newHeight)];
                             break;
                         case 4:
                             [view setFrame:CGRectMake(CGRectGetMaxX(view.frame),CGRectGetMaxY(view.frame), -newWidth, -newHeight)];
                             break;
                     }
                 }
                 completion:nil];
}

This should be the expected resulting upon zoomIn Animation: image

3
How do you know it isn't working? If you resize a UIImageView, it does not necessarily resize the image displayed by the UIImageView. So perhaps the image view is being resized as you expect. One way to find out: give the image view a background color so you can see where it really is, independently of the image it contains. - matt
However, if the UIImageView really isn't being resized as its superview is resized, then yes, there is something wrong with your constraints. - matt
The reason why I put a green background color is for me to test if it's working fine. The thing is, what ever the constraints I put, it's not working. Can you suggest anything? Thanks - Josh Byanec McFergan
If the green box doesn't move at all, it sounds to me like you made your constraints to the wrong thing (i.e. not to the yellow box that is its superview). Give your views in Interface Builder useful labels so that the constraints clearly tell you what views they are connecting. - matt
Oh, one more thing. Make sure your view hierarchy is right. The green and yellow boxes should not just be subviews of the main view (siblings): make sure the green boxes are inside the yellow boxes (as subviews of them), not merely in front of them. - matt

3 Answers

15
votes

When trying to animate with Auto Layout, you should not change view's frames directly. Instead, you should animate changes in constraints.

To access constraints from storyboard you can simply create IBOutlets for them.

[containerView layoutIfNeeded]; // complete pending layout operations (optional)
[UIView animateWithDuration:1.0 animations:^{

    // Update constraints
    self.viewConstraint1.constant = NEW_VALUE;
    self.viewConstraint2.constant = NEW_VALUE;

    // Animate the changes
    [containerView layoutIfNeeded]; 
}];

Note that you usually want to call layoutIfNeeded on the super view(or higher) of the view you are trying to animate.

I recommend reading more on Auto Layout in Apple's official guide.

2
votes

A tweak to the above answer, I used from within a UIViewController

  [self.view layoutIfNeeded];
  [UIView animateWithDuration:.5
                         animations:^{
                             myConstraint.constant = 64;
                             [self.view layoutIfNeeded];
                         }
                         completion:^(BOOL finished) {
                             // whatever
                         }];

Changes of note: Apple docs recommend using layoutIfNeeded, and calling this both before and within the animation block. This is so that you can be sure the animation stack is cleared before beginning.

Also, you are to call layoutIfNeeded on the parent view of the constraint you will be animating, not on the view who owns the constraint. Thanks to @nkukushkin for the initial answer.

It's also important to have your constraints set up correctly. The 'fix constraints' tool in IB won't necessary set them up in a way that works correctly for animating. For me I had to go through them and think through how I wanted the dependencies to work, which is of course expected but might not be obvious to the beginner (and results in errors).

2
votes

When you are using constrains, pre-constrains are generated. When you act on position and size, remove constrains while animating the view or do following:

yourView.translatesAutoresizingMaskIntoConstraints = YES;