Using autolayout constraints programmatically

2019-03-15 08:41发布

问题:

I'm trying to use autolayout in my iOS app programmatically. I have a simple view controller with this init code

UIView *innerView = [[UIView alloc] initWithFrame:self.view.bounds];

UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button1 setFrame:CGRectMake(50, 50, 150, 50)];
[button1 setTitle:@"button1" forState:UIControlStateNormal];

UIButton *button2 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button2 setFrame:CGRectMake(250, 50, 150, 50)];
[button2 setTitle:@"button2" forState:UIControlStateNormal];

[innerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|[button1][button2(==button1)]|" options:NSLayoutFormatAlignAllBaseline metrics:0 views:NSDictionaryOfVariableBindings(button1, button2)]];

[innerView addSubview:button1];
[innerView addSubview:button2];
[self.view addSubview:innerView];

But when I'm trying to run this, I'm getting this error:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse constraint format: 
Unable to interpret '|' character, because the related view doesn't have a superview 
|[button1][button2(==button1)]| 
          ^'

What's wrong with it?

And when I'm trying to remove pipes in constraintsWithVisualFormat, I'm getting this warning:

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) 
(
    "<NSAutoresizingMaskLayoutConstraint:0x716be10 h=--& v=--& UIRoundedRectButton:0x71631f0.midX == + 325>",
    "<NSAutoresizingMaskLayoutConstraint:0x7169940 h=--& v=--& H:[UIRoundedRectButton:0x715fb80(150)]>",
    "<NSAutoresizingMaskLayoutConstraint:0x7169860 h=--& v=--& UIRoundedRectButton:0x715fb80.midX == + 125>",
    "<NSLayoutConstraint:0x7164cd0 UIRoundedRectButton:0x71631f0.width == UIRoundedRectButton:0x715fb80.width>",
    "<NSLayoutConstraint:0x7164940 H:[UIRoundedRectButton:0x715fb80]-(0)-[UIRoundedRectButton:0x71631f0]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x7164940 H:[UIRoundedRectButton:0x715fb80]-(0)-[UIRoundedRectButton:0x71631f0]>

Break on objc_exception_throw to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

And as result of this, my constraints have no effect at all. What am I doing wrong?

回答1:

You have three problems:

First, you need to opt-in to layout based contraints on your both your button subviews

[button1 setTranslatesAutoresizingMaskIntoConstraints:NO];
[button2 setTranslatesAutoresizingMaskIntoConstraints:NO]; 

This will get rid of the NSAutoresizingMaskLayoutConstraint errors. Now you can get onto what's going on with your layout constraints.

Second, you have to addSubview before adding the constraints. You are calling addContraints on innerView before button1 and button2 are subviews of innerview.

Third, you should specify (although the docs indicate it is optional) whether the layout string is vertical or horizontal. @"H:|[button1][button2(==button1)]|". You will also want a vertical constraint like @"V:[button1]|" which would align button1 to the bottom of innerview and because you have aligned baselines on the buttons, button2 will follow.



回答2:

Just for the record: the exception concerning the missing superview gets already triggered by constraintsWithVisualFormat not addConstraints