Reputation: 33101
I have a simple layout where there is a containerView
that starts on the entire screen. Inside, I have two vertical subviews — topView (green), botView (orange)
which need equal heights and should have 50% of the containerView
height.
After launch, I slide in a view (blue) from offscreen up from the bottom, causing the containerView
to resize to a shorter height.
What I would expect to happen is that the topView
and botView
would both get shorter, maintaining their even heights within the containerView
, but what actually happens is that the inner views are not resized, despite having a constraint to do so.
Because this code has some code based constraints, and some IB ones, here is a sample project to see it in action. This is the constraint which is being ignored:
NSLayoutConstraint *c1 = [NSLayoutConstraint constraintWithItem:self.topView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.containerView
attribute:NSLayoutAttributeHeight
multiplier:0.5f
constant:0.f];
[self.containerView addConstraint:c1];
and the resize view code:
- (void)resizeViews {
__weak UAViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:0.25 animations:^{
weakSelf.slideInView.frame = CGRectMake(CGRectGetMinX(weakSelf.view.bounds),
CGRectGetMaxY(weakSelf.view.bounds) - CGRectGetHeight(weakSelf.slideInView.frame),
CGRectGetWidth(weakSelf.view.bounds),
CGRectGetHeight(weakSelf.slideInView.frame));
weakSelf.containerView.frame = CGRectMake(CGRectGetMinX(weakSelf.view.bounds),
CGRectGetMinY(weakSelf.view.bounds),
CGRectGetWidth(weakSelf.view.bounds),
CGRectGetMaxY(weakSelf.view.bounds) - CGRectGetHeight(weakSelf.slideInView.frame));
}];
});
}
What am I doing wrong here?
Upvotes: 2
Views: 4311
Reputation: 437442
I'm surprised you're setting the frame
for a view. Generally in auto layout, you'd slide in the view by changing a constraint constant
, not by changing a frame
.
For example, imagine that your constraints for the container's subviews are defined like so (for simplicity's sake, since the two views are supposed to take up 50% of the container, most easily done by defining the two subviews to be the same height):
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[topView][botView(==topView)]|" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[topView]|" options:0 metrics:nil views:views]];
[containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[botView]|" options:0 metrics:nil views:views]];
And, to keep things simple, define the relation between the container, the slide in view with relation to their superview like so:
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[containerView][slideInView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[containerView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[slideInView]|" options:0 metrics:nil views:views]];
// set the slide in view's initial height to zero
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:slideInView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
[self.view addConstraint:heightConstraint];
Then, when you want to slide in the "slide in view", just animate the changing of its height accordingly:
heightConstraint.constant = 100;
[UIView animateWithDuration:1.0 animations:^{
[self.view layoutIfNeeded];
}];
Thus:
Now, you can do this with heights that are x% of the height of the container, too, but you just can't do that easily with VFL, but it should work fine. Also you could slide in that "slide in view" by animating its top constraint, too (but that's a hassle because then you have to recalculate the top constraint on rotation, something I didn't want to do in this simple mockup).
But you get the idea. Just define the height or bottom constraint of the container view to be in relation to the slide in view, and then animate the slide in view by adjusting its constraints, and if you've defined all of your constraints properly, it will gracefully animate all four views (the container, the slide in view, and the container's two subviews) properly when you animate layoutIfNeeded
after changing the slide in view's constraints.
Upvotes: 4