自动布局让我的生活很困难。从理论上讲,当我转换的时候,它会非常有用,但我似乎一直在与它作斗争。

我做了一个演示项目来寻求帮助。有人知道如何使视图之间的空间增加或减少均匀,每当视图调整大小?

下面是三个标签(手动垂直对齐):

我想要的是,当我旋转时,它们均匀地调整间距(而不是视图大小)。默认情况下,顶部和底部视图向中心挤压:


当前回答

查看https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html,上面有关于解决问题的详细描述。

其他回答

在InterfaceBuilder中解决这个问题非常简单:

设置居中标签(label2)为“水平容器中心”和“垂直容器中心”

选择居中标签和顶部标签(label1 + label2),并为垂直间距添加两个约束。大于或等于最小间距的一个。小于或等于最大间距的一个。

中间的标签和底部的标签(label2 + label3)也是如此。

此外,您还可以添加两个约束label1 -顶部空间到SuperView和两个约束label2 -底部空间到SuperView。

结果是所有4个空格的大小变化相同。

我知道距离第一个答案已经有一段时间了,但我刚刚遇到了同样的问题,我想分享我的解决方案。为了子孙后代……

我在viewDidLoad上设置了视图:

- (void)viewDidLoad {

    [super viewDidLoad];

    cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [self.view addSubview:cancelButton];

    middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    middleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
    [self.view addSubview:middleButton];

    nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    [nextButton setTitle:@"Next" forState:UIControlStateNormal];
    [self.view addSubview:nextButton];


    [self.view setNeedsUpdateConstraints];

}

然后,在updateViewConstrains上,首先删除所有约束,然后创建视图字典,然后计算视图之间使用的空间。在那之后,我只是使用视觉语言格式设置约束:

- (void)updateViewConstraints {


    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);

    float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
    NSNumber *distancies=[NSNumber numberWithFloat:distance];

//    NSLog(@"Distancies: %@", distancies);
//    
//    NSLog(@"View Width: %f", self.view.bounds.size.width);
//    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
//    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
//    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);



    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                   options:NSLayoutFormatAlignAllBaseline
                                                                   metrics:@{@"dis":distancies}
                                                                     views:viewsDictionary];


    [self.view addConstraints:constraints];



    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                          options:0
                                                          metrics:nil
                                                            views:viewsDictionary];
    [self.view addConstraints:constraints];



}

这种方法的好处是你只需要做很少的数学运算。我并不是说这是完美的解决方案,但我为我试图实现的布局工作。

我希望这能有所帮助。

Android has a method of chaining views together in its constraint based layout system that I wanted to mimic. Searches brought me here but none of the answers quite worked. I didn't want to use StackViews because they tend to cause me more grief down the line than they save up front. I ended up creating a solution that used UILayoutGuides placed between the views. Controlling their width's allows different types of distributions, chain styles in Android parlance. The function accepts a leading and trailing anchor instead of a parent view. This allows the chain to be placed between two arbitrary views rather than distributed inside of the parent view. It does use UILayoutGuide which is only available in iOS 9+ but that shouldn't be a problem anymore.

public enum LayoutConstraintChainStyle {
    case spread //Evenly distribute between the anchors
    case spreadInside //Pin the first & last views to the sides and then evenly distribute
    case packed //The views have a set space but are centered between the anchors.
}

public extension NSLayoutConstraint {

    static func chainHorizontally(views: [UIView],
                                  leadingAnchor: NSLayoutXAxisAnchor,
                                  trailingAnchor: NSLayoutXAxisAnchor,
                                  spacing: CGFloat = 0.0,
                                  style: LayoutConstraintChainStyle = .spread) -> [NSLayoutConstraint] {
    var constraints = [NSLayoutConstraint]()
    guard views.count > 1 else { return constraints }
    guard let first = views.first, let last = views.last, let superview = first.superview else { return constraints }

    //Setup the chain of views
    var distributionGuides = [UILayoutGuide]()
    var previous = first
    let firstGuide = UILayoutGuide()
    superview.addLayoutGuide(firstGuide)
    distributionGuides.append(firstGuide)
    firstGuide.identifier = "ChainDistribution\(distributionGuides.count)"
    constraints.append(firstGuide.leadingAnchor.constraint(equalTo: leadingAnchor))
    constraints.append(first.leadingAnchor.constraint(equalTo: firstGuide.trailingAnchor, constant: spacing))
    views.dropFirst().forEach { view in
        let g = UILayoutGuide()
        superview.addLayoutGuide(g)
        distributionGuides.append(g)
        g.identifier = "ChainDistribution\(distributionGuides.count)"
        constraints.append(contentsOf: [
            g.leadingAnchor.constraint(equalTo: previous.trailingAnchor),
            view.leadingAnchor.constraint(equalTo: g.trailingAnchor)
        ])
        previous = view
    }
    let lastGuide = UILayoutGuide()
    superview.addLayoutGuide(lastGuide)
    constraints.append(contentsOf: [lastGuide.leadingAnchor.constraint(equalTo: last.trailingAnchor),
                                    lastGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
    distributionGuides.append(lastGuide)

    //Space the according to the style.
    switch style {
    case .packed:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalTo: first.widthAnchor))
            constraints.append(contentsOf:
                distributionGuides.dropFirst().dropLast()
                    .map { $0.widthAnchor.constraint(equalToConstant: spacing) }
                )
        }
    case .spread:
        if let first = distributionGuides.first {
            constraints.append(contentsOf:
                distributionGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: first.widthAnchor) })
        }
    case .spreadInside:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(equalToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalToConstant: spacing))
            let innerGuides = distributionGuides.dropFirst().dropLast()
            if let key = innerGuides.first {
                constraints.append(contentsOf:
                    innerGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: key.widthAnchor) }
                )
            }
        }
    }

    return constraints
}

我也有类似的问题,发现了这篇文章。但是,目前提供的答案中没有一个能以您想要的方式解决问题。他们没有使间距相等,而是平均分配标签的中心。重要的是要明白这是不一样的。我画了一个小图来说明这一点。

有3个视图,都是20点高。使用任何建议的方法都可以均匀地分布视图的中心,并为您提供插图布局。注意,视图的y中心间隔相等。但是,父视图和顶视图之间的间距是15pt,而子视图之间的间距只有5pt。为了使视图间距相等,这两个视图的间距都应该是10pt,即所有蓝色箭头的间距都应该是10pt。

然而,我还没有想出一个好的通用解决方案。目前我最好的想法是插入“间距视图”之间的子视图和设置间距视图的高度相等。

我刚刚用乘数特性解决了我的问题。我不确定它是否适用于所有情况,但对我来说,它非常有效。我在Xcode 6.3供你参考。

我最后做的是:

1)首先将我的按钮放置在320px宽度的屏幕上,以我希望它在320px设备上的方式分布。

2)然后我在所有按钮的superview上添加了一个领先的空间约束。

3)然后我修改了前导空间的属性,使常量为0,乘数是x偏移量除以屏幕宽度(例如,我的第一个按钮距离左边缘8px,所以我将乘数设置为8/320)

4)那么这里重要的一步是将约束关系中的第二个Item更改为superview。尾随而不是superview.leading。这很关键,因为superview。在我的例子中,前导为0,后拖为320,所以8/320在320px设备上是8px,然后当父视图的宽度改变为640或其他什么时,视图都以相对于320px屏幕大小的宽度的比例移动。这里的数学比较容易理解。