使用NSLayoutConstraint垂直居中两个视图

时间:2013-06-25 10:20:21

标签: ios uikit autolayout nslayoutconstraint

想象一下这个场景。你有一个UIImageView和一个UIButton。第一个是300x360,第二个是210x70。 imageview包含目录图像,button表示“打开目录”。

我想根据这些要求在主视图中定位元素:

  • 两个元素应该水平居中,即center.x坐标应该全部相等(视图,图像和按钮);

  • 这两个元素应按以下方式垂直居中:分隔符(灵活) - imageview - 分隔符(固定,假设30分) - 按钮 - 分隔符(灵活)。最上面和最下面的分隔符应该具有相同的大小(这是居中的含义)。

我无法使用NSLayoutConstraint使其工作。

到目前为止,我所做的一直是使用NSLayoutAttributeCenterXNSLayoutRelationEqual将两个元素的X坐标居中到相同的view属性。

根据我的想法,最后一部分是修复它们的垂直对齐。 我尝试使用@"V:|-[imageview(360)]-[button(70)]-|",但无效(Unable to simultaneously satisfy constraints.)。

如果我使用@"V:|-[imageview(360)]-[button]-|",我会把一切都搞定。也就是说,顶部是完美的,但按钮是拉伸的,以填补内部分隔符和视图底部之间的空隙。

如何让这些元素固定大小,让自动布局只是弄清楚如何将它们放在视图中?

3 个答案:

答案 0 :(得分:10)

我能够通过做这样的事情来做到这一点:

NSNumber *sepHeight = @60.0F;

// Center the two views horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:imageView
                                                      attribute:NSLayoutAttributeCenterX
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeCenterX
                                                     multiplier:1
                                                       constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                      attribute:NSLayoutAttributeCenterX
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeCenterX
                                                     multiplier:1
                                                       constant:0]];

// Position the two views one below the other, using the separator height defined above
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[imageview]-sepHeight-[button]"
                                                                  options:0
                                                                  metrics:NSDictionaryOfVariableBindings(sepHeight)
                                                                    views:views]];

// Force the button distance from the bottom to be the half of the size of the content
CGFloat constant = (imageview.frame.size.height + button.frame.size.height + [sepHeight floatValue]) / 2.0;
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                      attribute:NSLayoutAttributeBottom
                                                      relatedBy:NSLayoutRelationEqual
                                                         toItem:self.view
                                                      attribute:NSLayoutAttributeCenterY
                                                     multiplier:1
                                                       constant:constant]];

棘手的部分是常数值。该值是所有视图高度的一半,包括它们的分隔符。这意味着,如果imageview的高度为360,按钮的高度为70,分隔符为60,则该常量将为(360 + 70 + 60)/ 2 = 245。

确实应该有一种更聪明的方式,但是现在我认为这没问题。

答案 1 :(得分:5)

有两种方法可以解决这个问题。

  1. 正如@uchuugaka建议的那样,将您的imageview和按钮放在容器视图中。如果将子视图固定到容器的边缘(您将相应地调整大小 - 高度为360 + 30 + 70 == 460),则不会出现相同的居中问题。然后,您可以将此容器置于视图的中心位置简单的align-center-Y约束。

  2. 您可以使用间隔视图。通过添加两个隐藏视图,您可以指定约束以将它们定位在图像视图和按钮的上方/下方,具有相同的高度,例如它们充当弹簧。以下是使用您的维度执行此操作的代码:

  3. 
    - (void) viewDidLoad
    {
        [super viewDidLoad];
    
        UIView* imageview = [UIView new];
        imageview.backgroundColor = [UIColor blueColor];
        imageview.translatesAutoresizingMaskIntoConstraints = NO;
    
        UIView* button = [UIView new];
        button.backgroundColor = [UIColor greenColor];
        button.translatesAutoresizingMaskIntoConstraints = NO;
    
    
        UIView* spacer1 = [UIView new];
        spacer1.backgroundColor = [[UIColor redColor] colorWithAlphaComponent: 0.5];
        spacer1.translatesAutoresizingMaskIntoConstraints = NO;
        spacer1.hidden = YES; // comment out to show spacer!
    
        UIView* spacer2 = [UIView new];
        spacer2.backgroundColor = [[UIColor redColor] colorWithAlphaComponent: 0.5];
        spacer2.translatesAutoresizingMaskIntoConstraints = NO;
        spacer2.hidden = YES; // comment out to show spacer!
    
        [self.view addSubview: imageview];
        [self.view addSubview: button];
        [self.view addSubview: spacer1];
        [self.view addSubview: spacer2];
    
        NSDictionary* views = NSDictionaryOfVariableBindings( imageview, button, spacer1, spacer2 );
    
        NSArray* constraints;
        constraints = [NSLayoutConstraint constraintsWithVisualFormat: @"V:|[spacer1(==spacer2)][imageview(360)]-30-[button(70)][spacer2(==spacer1)]|"
                                                              options: 0
                                                              metrics: nil
                                                                views: views];
        [self.view addConstraints: constraints];
    
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:imageview
                                                              attribute:NSLayoutAttributeWidth
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:nil
                                                              attribute:NSLayoutAttributeNotAnAttribute
                                                             multiplier:1
                                                               constant:300]];
    
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                              attribute:NSLayoutAttributeWidth
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:nil
                                                              attribute:NSLayoutAttributeNotAnAttribute
                                                             multiplier:1
                                                               constant:210]];
    
    
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:imageview
                                                              attribute:NSLayoutAttributeCenterX
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeCenterX
                                                             multiplier:1
                                                               constant:0]];
    
        [self.view addConstraint:[NSLayoutConstraint constraintWithItem:button
                                                              attribute:NSLayoutAttributeCenterX
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeCenterX
                                                             multiplier:1
                                                               constant:0]];
    }
    

答案 2 :(得分:0)

您需要使垂直空间等于或大于图像视图顶部和按钮底部。 但是,这听起来似乎更容易在包含图像和按钮的其他视图上。然后在超视图中将视图V和H居中。

自动布局有时仍表示容器视图。