使用“自动布局”定义可能的0值

时间:2015-10-22 02:47:53

标签: ios autolayout

我有一个包含三个子视图的视图。这些子视图应缩放以填充视图的整个宽度。

我尝试过使用此约束:

NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeWidth multiplier:((1 / 3) * idx) constant:0.0];

这会导致异常:

  

+ [NSLayoutConstraint constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:]:   乘数0或零秒项以及位置   第一个属性创建位置相等的非法约束   一个常数。必须成对指定位置属性'

我理解它在抱怨什么但似乎令人费解,我无法得到这种行为。我希望我的第一个视图的x原点为0。

还有另一种方法可以让它发挥作用吗?

3 个答案:

答案 0 :(得分:1)

  1. 您无法使位置NSLayoutAttributeLeft等于宽度NSLayoutAttributeWidth
  2. 例外情况表示您使用的乘数为0.因为您将乘数参数设置为((1 / 3) * idx),我认为idxint类型。因此表达式((1 / 3) * idx)的计算结果为0.如果要使用浮点乘数,可以通过将三个数中的任何一个更改为浮点类型来实现,例如((1 / 3.0) * idx)
  3. 如果您只有3个子视图进行布局,则可视格式可能是一种更简单易读的应用方式。假设您希望缩放3个子视图以填充containerView,它们都具有相等的宽度。代码如下:

    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];
    

    更一般地说,您可能有超过3个子视图或必须在运行时决定它。对于这种情况,for循环可能会有所帮助:

    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;
    }
    

答案 1 :(得分:1)

如果您的部署目标是iOS 9.0或更高版本,那么将这三个子视图放入UIStackView可能会更简单。默认的堆栈视图设置应该按照您的需要进行:水平放置三个视图,端对端,拉伸以填充堆栈视图的宽度,中间没有填充。

答案 2 :(得分:0)

如您所知,您无法创建仅将坐标指定为常量的约束。相反,创建一个相对于某个“里程碑”的人。在这种情况下,由于您希望原点的x坐标为0,这意味着视图的左边缘将与其超视图的左边缘重合。因此,创建一个建立该关系的约束:

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:smallView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:containerView attribute:NSLayoutAttributeLeft multiplier:1 constant:0.0];

它必须与其他两个不同,尽管实现这种分裂的通常方法是:

  • superview.leading == view1.leading
  • view1.trailing == view2.leading
  • view2.trailing == view3.leading
  • view3.trailing == superview.trailing
  • view1.width == view2.width
  • view2.width == view3.width

(请注意,我使用的是前导和尾随而不是左右。这使得您的UI会自动镜像从右到左的语言。)