Reputation: 21
I am new to autolayout programming. I'm trying to make a View(Button) that is show/hide on click of a button. I'm able to achieve my target but it throws an exception.
Here is my code:
@interface RootViewController ()
{
NSArray *hiddenState;
NSArray *visibleState;
NSArray *verticalState;
UIButton *btnLeft;
}
- (void)viewDidLoad
{
[super viewDidLoad];
btnLeft = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnLeft.backgroundColor = [UIColor greenColor];
btnLeft.translatesAutoresizingMaskIntoConstraints = NO;
btnLeft.selected = NO;
[self.view addSubview:btnLeft];
NSString *verticalConstraint = @"V:|[v]|";
NSMutableDictionary *views = [NSMutableDictionary new];
views[@"v"] = btnLeft;
views[@"superview"] = self.view;
if ([self respondsToSelector:@selector(topLayoutGuide)]) {
views[@"topLayoutGuide"] = self.topLayoutGuide;
verticalConstraint = @"V:|[topLayoutGuide][v]|";
}
verticalState = [NSLayoutConstraint constraintsWithVisualFormat:verticalConstraint options:0 metrics:nil views:views];
hiddenState = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[v(==0)]|" options:0 metrics:nil views:views];
visibleState = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[v]-50-|" options:0 metrics:nil views:views];
[self.view addConstraints:verticalState];
[self.view addConstraints:hiddenState];
}
- (IBAction)leftButtonAction:(id)sender
{
UIButton *btn = (UIButton *)sender;
if (btn.selected)
{
[self.view removeConstraints:visibleState];
[self.view addConstraints:hiddenState];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
btn.selected = NO;
}];
}
else
{
[self.view removeConstraints:hiddenState];
[self.view addConstraints:visibleState];
[UIView animateWithDuration:0.5 animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
btn.selected = YES;
}];
}
}
This throws the following exception:
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:0x7d24d380 H:|-(0)-[UIButton:0x7bf58f70] (Names: '|':UIView:0x7bf4c080 )>",
"<NSLayoutConstraint:0x7d245de0 H:[UIButton:0x7bf58f70(0)]>",
"<NSLayoutConstraint:0x7d245e10 H:[UIButton:0x7bf58f70]-(0)-| (Names: '|':UIView:0x7bf4c080 )>",
"<NSLayoutConstraint:0x7d2ad6f0 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7bf4c080(320)]>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x7d245e10 H:[UIButton:0x7bf58f70]-(0)-| (Names: '|':UIView:0x7bf4c080 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.
It throws the exception when I am trying to make button width equal to zero.
Upvotes: 1
Views: 4725
Reputation: 385910
Consider the first three constraints from the error message:
H:|-(0)-[UIButton:0x7bf58f70] (Names: '|':UIView:0x7bf4c080 )
H:[UIButton:0x7bf58f70(0)]
H:[UIButton:0x7bf58f70]-(0)-| (Names: '|':UIView:0x7bf4c080 )
Your H:|[v(==0)]|
format string creates these three constraints. We can write them as equations like this:
(1) superview.leading == button.leading
(2) button.leading == button.trailing
(3) button.trailing == superview.trailing
Substitute (2) into (1) to get this:
(4) superview.leading == button.trailing
Then substitute (3) into (4) to get this:
(5) superview.leading == superview.trailing
This means the superview must have width 0.
Now consider the last constraint in the error message:
H:[UIView:0x7bf4c080(320)]
The system adds this constraint, presumably because this is the root view controller's view is therefore sized to fill the screen. This constraint says the superview must have width 320. This conflicts with equation (5). That's why you get the error.
I assume you want the button to stick to the left edge of the superview, since you've named it btnLeft
. So try these constraints instead:
hiddenState = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[v(==0)]" options:0 metrics:nil views:views];
visibleState = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[v]" options:0 metrics:nil views:views];
Upvotes: 1