Zigii Wong
Zigii Wong

Reputation: 7826

iAutoLayout crash when setting Visual Format Language

HI I am setting my views using autoLayouts with visual format language.

I add some constraints to my views.

Here are my codes how I set up:

- (void)viewDidLoad
{
self.first  = [UIView new];
self.second = [UIView new];
self.third  = [UIView new];
self.fourth = [UIView new];
self.fifth  = [UIView new];

self.first.translatesAutoresizingMaskIntoConstraints  = NO;
self.second.translatesAutoresizingMaskIntoConstraints = NO;
self.third.translatesAutoresizingMaskIntoConstraints  = NO;
self.fourth.translatesAutoresizingMaskIntoConstraints = NO;
self.fifth.translatesAutoresizingMaskIntoConstraints  = NO;

[self.view addSubview:self.first];
[self.view addSubview:self.second];
[self.view addSubview:self.third];
[self.view addSubview:self.fourth];
[self.view addSubview:self.fifth];

NSDictionary *dictionary = NSDictionaryOfVariableBindings(_first, _second, _third, _fourth, _fifth);

NSArray *constraintsArray;
NSString *format;

format = @"|[_first][_second][_third][_fourth][_fifth]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

format = @"V:|[_first]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

format = @"V:|[_second]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

format = @"V:|[_third]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

format = @"V:|[_fourth]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

format = @"V:|[_fifth]|";
constraintsArray = [NSLayoutConstraint constraintsWithVisualFormat:format options:NSLayoutFormatAlignAllLeft metrics:nil views:dictionary];
[self.view addConstraints:constraintsArray];

}

Here is what i want the five UIViews act as. They have same WIDTH and HEIGHT and there are no margin on both size.(The first one and the last one) . That's say, they are filled within there container view, in this case, (self.view)

enter image description here

When I run, the app crash:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unable to parse   constraint format: 
Options mask required views to be aligned on a horizontal edge, which is not allowed for layout that is also horizontal. 
|[_first][_second][_third][_fourth][_fifth]| 
                  ^'

What I had done wrong? Please help me. Thanks.

Upvotes: 2

Views: 1035

Answers (2)

user2103679
user2103679

Reputation:

format string proposed by Rob is perfect. You can also avoid all the other vertical constraints just adding 'NSLayoutFormatAlignAllTop' instead of 'NSLayoutFormatAlignAllLeft'. Basically when you deal with a format string related to horizontal axis you must use alignment options that relate to vertical axis and vice versa ( option is perpendicular to format string ), or if you don't need it just pass 0. Your only one method should look like this:

NSString format = @"H:|[_first][_second(==_first)][_third(==_first)][_fourth(==_first)][_fifth(==_first)]|";

[NSLayoutConstraint constraintsWithVisualFormat:format 
                                        options:NSLayoutFormatAlignAllTop
                                        metrics:nil
                                          views:dictionary];

[EDIT]

Rob's right. NSLayoutFormatAlignAllTop aligns all top side of views inside the format string between them and not to their superview. You have to add one vertical pin constraint to only one of your view and all the others will also align because of 'NSLayoutFormatAlignAllTop'. Also to remove ambiguous layout you need to add a height constraint. This is the code i tried (with a 100 point height) and doesn't give me ambiguous layout:

NSDictionary *dictionary = NSDictionaryOfVariableBindings(_first, _second, _third, _fourth, _fifth);


NSString *format = @"H:|[_first][_second(==_first)][_third(==_first)][_fourth(==_first)][_fifth(==_first)]|";

NSMutableArray *constraintsArray =  [NSLayoutConstraint constraintsWithVisualFormat:format
                                                                           options:NSLayoutFormatAlignAllTop
                                                                           metrics:nil
                                                                             views:dictionary].mutableCopy;

[constraintsArray addObject:[NSLayoutConstraint constraintWithItem:_first
                                                         attribute:NSLayoutAttributeTop
                                                         relatedBy:NSLayoutRelationEqual
                                                            toItem:_first.superview
                                                         attribute:NSLayoutAttributeTop
                                                        multiplier:1.0 constant:0]];

CGFloat height = 100;

for (UIView *view in @[_first,_second,_third,_fourth,_fifth]) {
    [constraintsArray addObject:[NSLayoutConstraint constraintWithItem:view
                                                             attribute:NSLayoutAttributeHeight
                                                             relatedBy:NSLayoutRelationEqual
                                                                toItem:nil
                                                             attribute:NSLayoutAttributeNotAnAttribute
                                                            multiplier:1.0
                                                              constant:height]];


}


[self.view addConstraints:constraintsArray];

Upvotes: 1

Rob
Rob

Reputation: 437882

You should remove all of those references to NSLayoutFormatAlignAllLeft.

Also, unrelated, but you are missing the constraint that makes them the same width. I'd replace the horizontal constraint with:

format = @"H:|[_first][_second(==_first)][_third(==_first)][_fourth(==_first)][_fifth(==_first)]|";

Upvotes: 4

Related Questions