【问题标题】:Horizontally align buttons in a view using autolayout programatically以编程方式使用自动布局在视图中水平对齐按钮
【发布时间】:2015-01-19 20:42:00
【问题描述】:

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

这适用于具有短标题的按钮:

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

但是一旦其中一个按钮的标题变长了,它就会像这样中断:

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

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

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

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

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

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

--- 更新 ---

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

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

最终结果:

【问题讨论】:

  • 不清楚您希望按钮的外观。您是否希望它们每个都有足够的宽度来显示它们的标题,但仍扩展到视图的宽度(减去 10-5-10 填充)?您是否希望它们都具有相同的宽度,但在必要时减小字体大小(我很确定在不计算标题大小的情况下无法以任何简单的方式做到这一点)?

标签: ios autolayout nslayoutconstraint


【解决方案1】:

使用抗内容压缩优先级

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

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

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

因此,如果内容可以适合这些标签:

但如果其中一个变长:

Content Compression Resistance Priority 是一种告诉自动布局您希望组件保持其固有尺寸多远(因此称为抗压缩性)的方法。

这种方法也可以在 IB 中更容易地实现。内容阻力优先级可以在 Size Inspector 选项卡中设置 (cmd + opt + 5)。

【讨论】:

  • 谢谢,添加这些优先的部分改进了一切;)我还添加了一些东西来使我的按钮减小字体大小,并且如果需要,它们的标题可以分成多行。 btn.contentEdgeInsets = UIEdgeInsetsMake(0, 5, 0, 5); btn.titleLabel.adjustsFontSizeToFitWidth = YES; btn.titleLabel.numberOfLines = 0; btn.titleLabel.minimumScaleFactor = 0.7;
【解决方案2】:

如果您使用自动布局,您可以简单地使用约束来确保您的按钮始终对齐,无论是垂直还是水平。为了水平对齐它们(即对齐它们的 y 值相同),只需按住命令并分别单击它们来选择两个按钮:

它们将出现在 Storyboard 中,周围带有选择器指示符。现在转到右下角并选择对齐他们的“垂直中心”。对齐它们的垂直中心将使它们水平对齐(基于您的图表)。

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

要解决您关于文本扩展的问题,我能想到的一种解决方法是创建一个 UIView,然后在其中放置一个 UILabel 来模拟一个按钮.您必须将视图链接到某个 IBOutlet 以在按下它时获取并将其链接到您希望它执行的功能。但是 UILabel 具有您可以在 Storyboard 中使用属性检查器设置的属性:

如果您选择“最小字体大小”,设置该值,那么您的文本将自动缩小,因为它会填满分配的空间,如下所示:

【讨论】:

    【解决方案3】:

    随着文本增长到填充其宽度,您最终会遇到约束模糊性。不知道会发生什么!您需要使用约束优先级和不等式(可能还需要改变压缩阻力)来解决此问题。

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

        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)
        )
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多