使用autolayout以编程方式在视图中水平对齐按钮

时间:2014-11-21 16:19:42

标签: ios autolayout nslayoutconstraint

我正在尝试在视图中水平对齐两到三个按钮。为简单起见,我将展示我对齐两个按钮的尝试。

这适用于标题较短的按钮:

@"H:|-10-[questionButton1(questionButton2)]-5-[questionButton2]-10-|"

enter image description here

但是只要其中一个按钮获得更长的标题,就会像这样打破: enter image description here

我最终做的是计算每个按钮的宽度,然后如果button1宽度大于视图的一半并且大于button2宽度,我使用了:

@"H:|-10-[questionButton1(==btn1width)]-5-[questionButton2(>=btn2width)]-10-|"

它有点工作,但我不喜欢这种计算的代码外观。想象一下它增加了第三个按钮的复杂性。此外,如果两个按钮都具有相当长的标题,则会出现问题,在这种情况下,我必须弄清楚是否应该减小字体大小以使一切都合适。

我在这里发布这个是因为我可能会遗漏一些关于autolayout的神奇事情,因为我今天才开始在代码中使用它。任何形式的帮助将不胜感激。

---更新(澄清)---

我希望按钮分开考虑边距(外侧10个,按钮5个)。理想情况下,如果文本大小适合其默认大小,它们应该是相同的宽度(50%:两个按钮为50%,33%:33%:三个按钮为33%)。如果按钮标题超过完美宽度,如果其他按钮允许按钮(如果其他按钮可以缩小),按钮应该扩展其宽度。如果没有可能的扩展或缩小,则大按钮应减小字体大小并重复该过程(检查其他按钮是否可以缩小)。是的,我知道,我要求很多:)

how it looks when it works

---更新---

@Sikhapol的回答帮助我解决了这个问题。我添加了一些东西来减少字体大小,添加填充并使按钮标题在文本不适合时分成多行:

btn.contentEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5);
btn.titleLabel.adjustsFontSizeToFitWidth = YES;
btn.titleLabel.numberOfLines = 0;
btn.titleLabel.minimumScaleFactor = 0.7;

最终结果: end result

3 个答案:

答案 0 :(得分:8)

使用内容压缩阻力优先

您可以告诉自动布局尽量保持两个标签的相等宽度。但是你告诉它,让其中一个变得更大以适应内部的内容更重要。

为此,请将等宽约束的优先级设置为低于标签(或按钮)的内容压缩阻力优先级。

- (void)viewDidLoad {
    [super viewDidLoad];

    UILabel *label1 = [[UILabel alloc] init];
    label1.text = @"this seems";
    label1.backgroundColor = [UIColor orangeColor];
    label1.translatesAutoresizingMaskIntoConstraints = NO;

    UILabel *label2 = [[UILabel alloc] init];
    label2.text = @"completely fine";
    label2.backgroundColor = [UIColor orangeColor];
    label2.translatesAutoresizingMaskIntoConstraints = NO;

    [self.view addSubview:label1];
    [self.view addSubview:label2];

    NSDictionary *views = NSDictionaryOfVariableBindings(label1, label2);

    NSArray *horizontalConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[label1(label2)]-5-[label2]-10-|"
                                                                             options:NSLayoutFormatAlignAllCenterY
                                                                             metrics:nil
                                                                               views:views];

    // Find the equal width constraint and set priority to high (750)
    for (NSLayoutConstraint *constraint in horizontalConstraints) {
        if (constraint.firstAttribute == NSLayoutAttributeWidth) {
            constraint.priority = UILayoutPriorityDefaultHigh;
        }
    }

    [self.view addConstraints:horizontalConstraints];

    // Set content compression resistant to required (1000)
    [label1 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];
    [label2 setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal];

    // The below code is here to add the vertical center constraints. You can ignore it.
    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1
                                                           constant:0]];

    [self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2
                                                          attribute:NSLayoutAttributeCenterY
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterY
                                                         multiplier:1
                                                           constant:0]];
}

因此,如果内容可以放在这些标签内:

fit

但如果其中一个长得更长:

expand

内容压缩阻力优先级是一种告诉自动布局您希望组件保持多远的内在大小(因此名称压缩阻力)的方法。

这种方法也可以在IB中更容易实现。可以在尺寸检查器标签(cmd + opt + 5)中设置内容抵抗优先级。

答案 1 :(得分:2)

如果您正在使用自动布局,则只需使用约束即可确保按钮始终垂直或水平对齐。为了使它们水平对齐(即将它们的y值对齐),只需通过按住命令并单独单击它们来选择两个按钮: enter image description here

它们将出现在故事​​板中,并带有选择器指示器。现在转到右下角,选择对齐他们的"垂直中心"。对齐垂直中心将使它们水平对齐(根据您的图表)。

enter image description here

这可确保它们始终水平对齐。

要解决有关文本扩展的问题,我可以想到解决这个问题的方法是创建一个UIView然后将UILabel放入模拟按钮。您必须将视图链接到某个IBOutlet,以便在按下它时将其链接到您希望它执行的功能。但是UILabel具有您可以使用Attributes Inspector在此处显示的Storyboard中设置的属性:

enter image description here

如果您选择"最小字体大小",设置该值,那么您的文本将在填满分配的空间时自动缩小,如下所示:

enter image description here enter image description here

答案 2 :(得分:0)

随着文本增长以填充其宽度,最终会出现约束歧义。不知道将会发生什么!您需要使用约束优先级和不等式(以及可能改变的压缩阻力)来解决此问题。

这是我在两个标签之间消除歧义的代码,这样一个人可以牺牲另一个标签来增长:

    let p = self.lab2.contentCompressionResistancePriorityForAxis(.Horizontal)
    self.lab1.setContentCompressionResistancePriority(p+1, forAxis: .Horizontal)

但我还需要使用不等式来设置最初的宽度和间距:

    self.view.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "H:[v1(>=20)]-(>=20)-[v2(>=20)]", options: nil, metrics: nil, views: d)
    )