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

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

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

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


当前回答

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

我在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];



}

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

我希望这能有所帮助。

其他回答

我可以在IB中完全解决这个问题:

使约束使每个子视图的中心Y对齐到父视图的下边缘。 将每个约束的乘数设置为1/2n, 3/2n, 5/2n,…,n-1/2n,其中n是要分布的子视图的数量。

因此,如果您有三个标签,请将每个约束的乘数设置为0.1666667、0.5、0.833333。

我做了一个函数可能会有帮助。 用法示例:

 [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                asString:@[@"button1", @"button2", @"button3"]
                                                               alignAxis:@"V"
                                                          verticalMargin:100
                                                        horizontalMargin:50
                                                             innerMargin:25]];

会导致垂直分布(不好意思没有10个声望来嵌入图像)。如果你改变坐标轴和一些边距值

alignAxis:@"H"
verticalMargin:120
horizontalMargin:20
innerMargin:10

你会得到水平分布。

我是iOS的新手,但是voilà !

EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of subviews
 * to be evenly distributed along an axis.
 */
+ (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                               asString:(NSArray *) stringViews
                              alignAxis:(NSString *) axis
                         verticalMargin:(NSUInteger) vMargin
                       horizontalMargin:(NSUInteger) hMargin
                            innerMargin:(NSUInteger) inner;
@end

EvenDistribution.m

#import "EvenDistribution.h"

@implementation NSLayoutConstraint (EvenDistribution)

+ (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                              asString:(NSArray *) stringViews
                             alignAxis:(NSString *) axis
                        verticalMargin:(NSUInteger) vMargin
                      horizontalMargin:(NSUInteger) hMargin
                           innerMargin:(NSUInteger) iMargin

{
    NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
    NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                     axis,
                                     [axis isEqualToString:@"V"] ? vMargin : hMargin
                                     ];



        for (NSUInteger i = 0; i < dictViews.count; i++) {

            if (i == 0)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
            else if(i == dictViews.count - 1)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
            else
               [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];

            NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                     [axis isEqualToString:@"V"] ? @"H" : @"V",
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                     stringViews[i],
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin];

            [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:dictViews]];


    }
    [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                [axis isEqualToString:@"V"] ? vMargin : hMargin
                                ]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                             options:0
                                                                             metrics:nil
                                                                               views:dictViews]];

    return constraints;

}

@end

是的,你可以只在接口构建器中这样做,而不需要编写代码——需要注意的是,你是在调整标签的大小,而不是分配空白。在本例中,将标签2的X和Y对齐到父视图,使其固定在中心。然后将标签1的垂直空间设置为superview,标签2设置为standard,重复标签3。在设置标签2之后,设置标签1和3最简单的方法是调整它们的大小,直到它们断开。

这是水平显示,注意标签1和2之间的垂直空间被设置为标准:

这是竖屏版本:

我意识到,由于标签之间的标准空间和父视图的标准空间之间的差异,它们在基线之间不是绝对100%等间距的。如果这让您感到困扰,可以将大小设置为0而不是standard

查看开源库PureLayout。它提供了一些用于分布视图的API方法,包括每个视图之间的间距是固定的(视图大小根据需要而变化),以及每个视图的大小是固定的(视图之间的间距根据需要而变化)。请注意,所有这些都是在没有使用任何“间隔视图”的情况下完成的。

从NSArray + PureLayout.h:

// NSArray+PureLayout.h

// ...

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                         withFixedSpacing:(CGFloat)spacing;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                            withFixedSize:(CGFloat)size;

// ...

由于它都是开源的,如果您有兴趣了解如何在没有间隔视图的情况下实现这一点,只需查看实现即可。(这取决于同时利用约束的常数和乘数。)

非常快速的接口构建器解决方案:

对于在一个父视图中均匀间隔的任意数量的视图,简单地给每个水平布局的“对齐中心X到父视图”约束,或垂直布局的“对齐中心Y父视图”,并设置乘数为N:p(注意:有些人有更好的运气p:N -见下文)

在哪里

N =总视图数,和

P =包含空格的视图的位置

第一个位置是1,然后是一个空格,使得下一个位置是3,所以p变成了一个序列[1,3,5,7,9,…]。适用于任何数量的视图。

如果你有3个视图来分隔,它看起来是这样的:

编辑注意:N:p或p:N的选择取决于对齐约束的关系顺序。如果“第一项”是Superview。中心,你可以使用p:N,而如果Superview。中心是“第二项”,你可以用N:p。如果有疑问,可以两种都试一试。: -)