Reputation: 14304
The best solution for hiding views with the new Autolayout is definitely to create height constraint for the view, connect it and create an outlet for it, and change self.myViewHeightConstriant.constant equals to 0. But suppose the view contains some other views, suppose an imageView and some label below it. Now, the imageView is 10px away from the top and has top space to superview constraint with 10px value. Trying to hide container UIView with constant = 0 shows an error in console:
Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this: (1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't
understand, refer to the documentation for the UIView property
translatesAutoresizingMaskIntoConstraints)
(
<NSLayoutConstraint:0xc7cedb0 V:[UIView:0xc7ce1e0(0)]>,
<NSLayoutConstraint:0xc7ceea0 V:[UIImageView:0xc7ce270]-(0)-| (Names: '|':UIView:0xc7ce1e0 )>,
<NSLayoutConstraint:0xc7cef30 V:|-(10)-[UIImageView:0xc7ce270] (Names: '|':UIView:0xc7ce1e0 )>
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0xc7ceea0 V:[UIImageView:0xc7ce270]-(0)-| (Names: '|':UIView:0xc7ce1e0 )>
The guess the problem is container UIView has height 0, but the imageView has top space offset 10px from it and Autolayout engine doesn't understand how to handle this situation. Tried to set clipSubviews for container view but that didn't help. Any ideas?
UPDATE several thoughts, creating an outlet topSpaceToSuperView constraint for the imageView and set its constaint also to 0 doesn't look very appealing. There should be more elegant solution than trashing the code with multiple outlets...
Upvotes: 0
Views: 1761
Reputation: 211
If you have a leading, trailing, top, or bottom constraint you can set just set the relation to LessThanOrEqual when you hide it, and then back to equal when you show it.
Because relation is read-only, you'd do this by:
Essentially, all you're doing here is making that constraint small enough so that the height of your "big" view can == 0 when it's hidden.
Upvotes: 0
Reputation: 1577
You can't go simple with container.hidden = YES
?
Otherwise, it's the bottom constraint that's breaking things. @"V:|-10-[imageView]|"
tells the container view that has to be at least 10 pts tall. But @"V:|-10-[imageView]"
would be fine.
Perhaps instead of anchoring the imageView to the bottom of the container, setup a constraint for the imageView's height.
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[imageView]"
options:nil
metrics:nil
views:views];
[NSLayoutConstraint constraintWithItem:self.imageView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:self.containerView
attribute:NSLayoutAttributeHeight
multiplier:1.
constant:-10.f];
You mention in the comments that the imageView isn't a predictable height. Since that's the case, it might be easier to just manage the container's height, but do it with separate constraints:
containerOpen = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[imageView]|"
options:nil
metrics:nil
views:views];
containerClosed = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[containerView(0)]"
options:nil
metrics:nil
views:views];
// Toggle between the constraints to open close the container
- (void)toggleContainer
{
[self.containerView.superview removeConstraints:containerOpen];
[self.containerView.superview removeConstraints:containerClosed];
self.containerView.isOpen = !self.containerView.isOpen;
if (self.containerView.isOpen)
[self.containerView.superview addConstraints:containerOpen];
else
[self.containerView.superview addConstraints:containerClosed];
[self.containerView.superview setNeedsUpdateConstraints];
[self.containerView setNeedsLayout];
[self.containerView layoutIfNeeded];
}
Upvotes: 1