使用NSLayoutConstraint垂直居中两个视图

Fab*_*oni 6 uikit ios autolayout nslayoutconstraint

想象一下这个场景.你有一个UIImageView和一个UIButton.第一个是300x360,第二个是210x70.在imageview包含目录形象,button说"公开目录".

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

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

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

我无法使用NSLayoutConstraint使其工作.

到目前为止,我做什么,一直是围绕使用两个元素的X坐标NSLayoutAttributeCenterXNSLayoutRelationEqual相同的view属性.

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

如果我使用@"V:|-[imageview(360)]-[button]-|"我可以让一切都好.也就是说,顶部是完美的但是按钮被拉伸以填充内部分隔符和视图底部之间的间隙.

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

Fab*_*oni 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]];
Run Code Online (Sandbox Code Playgroud)

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

确实应该有一种更聪明的方式,但是现在我觉得这没关系.


Tom*_*ift 5

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

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

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


- (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]];
}
Run Code Online (Sandbox Code Playgroud)

  • 我喜欢spacer views的想法.除了它让我想起90的HTML spacer gif;) (2认同)