- You cannot make a location
NSLayoutAttributeLeft
equal to a width NSLayoutAttributeWidth
- The exception says you have used a multiplier of 0. Because you set the multiplier parameter to
((1 / 3) * idx)
, and I guess the idx
is a int
type. So the expression ((1 / 3) * idx)
evaluates to 0. If you want to use a float multiplier, you could achieve that by changing any one of the three numbers to a float type, for example, ((1 / 3.0) * idx)
.
If you have only 3 subviews to layout, visual format may be a simpler and easy to read way to apply. Say you want the 3 subviews to scale to fill the containerView
, all of them have an equal width. The code goes like this:
UIView *smallView0 = [UIView new];
smallView0.backgroundColor = [UIColor redColor];
smallView0.translatesAutoresizingMaskIntoConstraints = NO;
[containerView addSubview:smallView0];
UIView *smallView1 = [UIView new];
smallView1.backgroundColor = [UIColor blueColor];
smallView1.translatesAutoresizingMaskIntoConstraints = NO;
[containerView addSubview:smallView1];
UIView *smallView2 = [UIView new];
smallView2.backgroundColor = [UIColor greenColor];
smallView2.translatesAutoresizingMaskIntoConstraints = NO;
[containerView addSubview:smallView2];
NSDictionary *bindings = NSDictionaryOfVariableBindings(smallView0, smallView1, smallView2);
// Layout the three subviews to fill the `containerView`, and, make theirs widths equal.
NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|[smallView0][smallView1(==smallView0)][smallView2(==smallView0)]|" options:0 metrics:nil views:bindings];
[containerView addConstraints:hConstraints];
// The constraints below are set to satisfy the vertical layout rules. You may have your own choice.
NSArray *vConstraints0 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[smallView0]-|" options:0 metrics:nil views:bindings];
NSArray *vConstraints1 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[smallView1]-|" options:0 metrics:nil views:bindings];
NSArray *vConstraints2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[smallView2]-|" options:0 metrics:nil views:bindings];
[containerView addConstraints:vConstraints0];
[containerView addConstraints:vConstraints1];
[containerView addConstraints:vConstraints2];
More generally, you may have more than 3 subviews or have to decide it at runtime. For this case, a for loop could help:
UIView *previousView = nil;
int countOfSubviews = 6;
for (int i = 0; i < countOfSubviews; ++i) {
UIView *smallView = [UIView new];
[containerView addSubview:smallView];
smallView.backgroundColor = (i % 2 == 0) ? [UIColor redColor] : [UIColor greenColor];
smallView.translatesAutoresizingMaskIntoConstraints = NO;
NSLayoutConstraint *fixedHeight = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50];
[smallView addConstraint:fixedHeight];
if (i == 0) {
NSLayoutConstraint *left = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeLeft multiplier:1 constant:0];
[containerView addConstraint:left];
} else {
NSLayoutConstraint *internal = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:previousView attribute:NSLayoutAttributeRight multiplier:1 constant:0];
[containerView addConstraint:internal];
}
if (i == countOfSubviews - 1) {
NSLayoutConstraint *right = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeRight multiplier:1 constant:0];
[containerView addConstraint:right];
}
NSLayoutConstraint *verticalPostiion = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0];
[containerView addConstraint:verticalPostiion];
if (previousView) {
NSLayoutConstraint *equalWidth = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:previousView attribute:NSLayoutAttributeWidth multiplier:1 constant:0];
[containerView addConstraint:equalWidth];
}
previousView = smallView;
}