iOS Autolayout垂直等于空格以填充父视图

时间:2013-06-13 14:16:53

标签: ios autolayout

我有一个带有12 UITextField s。

的视图控制器

非常适合3.5英寸的显示器。

enter image description here

我需要将其设置为iPhone 5(4英寸显示屏),以便所有UITextField覆盖整个UIView,方法是在中间添加额外的空间。

我试图通过自动布局来做到这一点,但它无法正常工作。

enter image description here

这是我的代码:

- (void) viewWillLayoutSubviews
{
    int h = txt1.bounds.size.height * 12;

    float unusedHorizontalSpace = self.view.bounds.size.height - h ;

    NSNumber* spaceBetweenEachButton=  [NSNumber numberWithFloat: unusedHorizontalSpace / 13 ] ;

    NSMutableArray *constraintsForButtons = [[NSMutableArray alloc] init];

    [constraintsForButtons addObjectsFromArray: [NSLayoutConstraint constraintsWithVisualFormat: @"V:|-50-[txt1(==30)]-(space)-[txt2(==txt1)]-(space)-[txt3(==txt1)]-(space)-[txt4(==txt1)]-(space)-[txt5(==txt1)]-(space)-[txt6(==txt1)]-(space)-[txt7(==txt1)]-(space)-[txt8(==txt1)]-(space)-[txt9(==txt1)]-(space)-[txt10(==txt1)]-(space)-[txt11(==txt1)]-(space)-[txt12]-(space)-|"
                                                                                        options: NSLayoutFormatAlignAllCenterX
                                                                                        metrics: @{@"space":spaceBetweenEachButton}
                                                                                          views: NSDictionaryOfVariableBindings(txt1,txt10,txt11,txt12,txt2,txt3,txt4,txt5,txt6, txt7,txt8,txt9)]];

    [self.view addConstraints:constraintsForButtons];
}

如果我[txt12(==txt1)],则显示与3.5“屏幕相同的位置,并在下方留出空间。

我在哪里弄错了?

3 个答案:

答案 0 :(得分:49)

要使用自动布局执行此操作,您必须创建额外的视图以填充文本字段之间的空格。

回想一下,自动布局约束基本上是线性方程A = m * B + cA是一个视图的属性(例如,viewA的下边缘的Y坐标),B是另一个视图的属性(例如,{Y的Y坐标) {1}}的最高优势) viewBm是常量。因此,例如,要布置cviewA,以便在viewB的底部和viewA的顶部之间有30个点,我们可以创建约束viewB为1,m为-30。

您遇到的问题是,您希望在13个不同的约束中使用c的相同值,并且您希望自动布局为您计算c值。自动布局根本无法做到这一点。不是直接的。自动布局只能计算视图的属性;它无法计算cm常量。

有一种方法可以使自动布局将视图放在您想要的位置:将文本字段之间的空格作为附加(不可见)视图。这是一个只有3个文本字段的例子:

example layout

我们将创建一个约束,将每个spacer的上边缘固定到其上方文本字段的下边缘。我们还将创建一个约束,将每个spacer的底边固定到它下面的文本字段的顶边。最后,我们将创建一个约束来强制每个间隔物与最顶部的间隔物具有相同的高度。

我们需要两个实例变量来设置:文本字段的数组(按从上到下的顺序),以及对最顶层间隔视图的引用:

c

我们将在代码中创建文本字段和间隔符,因为很难在stackoverflow答案中显示xib。我们在@implementation ViewController { NSMutableArray *textFields; UIView *topSpacer; }

开始了
viewDidLoad

由于我们将使用自动布局,因此我们需要关闭- (void)viewDidLoad { [super viewDidLoad]; self.view.translatesAutoresizingMaskIntoConstraints = NO; [self addTextFields]; [self addSpacers]; } 以防止系统创建额外的约束。

我们创建每个文本字段,为其提供一些虚拟文本,并为其水平位置和大小设置约束:

translatesAutoresizingMaskIntoConstraints

我们也会使用一个循环来创建垫片,但是我们创建的顶部和底部垫片与中间垫片不同,因为我们需要将顶部和底部垫片固定到superview:

- (void)addTextFields {
    textFields = [NSMutableArray array];
    for (int i = 0; i < 12; ++i) {
        [self addTextField];
    }
}

- (void)addTextField {
    UITextField *field = [[UITextField alloc] init];
    field.backgroundColor = [UIColor colorWithHue:0.8 saturation:0.1 brightness:0.9 alpha:1];
    field.translatesAutoresizingMaskIntoConstraints = NO;
    field.text = [field description];
    [self.view addSubview:field];
    [field setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
    [field setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[field]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(field)]];
    [textFields addObject:field];
}

以下是我们如何创建顶部间隔并设置其约束。其上边缘固定在superview上,其下边缘固定在第一个(最顶部)文本字段上。我们将顶部间隔物存储在实例变量- (void)addSpacers { [self addTopSpacer]; for (int i = 1, count = textFields.count; i < count; ++i) { [self addSpacerFromBottomOfView:textFields[i - 1] toTopOfView:textFields[i]]; } [self addBottomSpacer]; } 中,这样我们就可以将其他间隔物限制为与顶部间隔物具有相同的高度。

topSpacer

以下是我们实际创建间隔视图的方法。这只是一个隐藏的视图。由于我们不关心其水平尺寸或位置,我们只需将其固定在超视图的左右边缘。

- (void)addTopSpacer {
    UIView *spacer = [self newSpacer];
    UITextField *field = textFields[0];
    [self.view addConstraints:[NSLayoutConstraint
        constraintsWithVisualFormat:@"V:|[spacer][field]" options:0 metrics:nil
        views:NSDictionaryOfVariableBindings(spacer, field)]];
    topSpacer = spacer;
}

要在两个文本视图之间创建“中间”间隔,我们将其固定到文本的下边缘 上方的字段和下方文本字段的上边缘。我们还将其高度限制为等于顶部间隔物的高度。

- (UIView *)newSpacer {
    UIView *spacer = [[UIView alloc] init];
    spacer.hidden = YES; // Views participate in layout even when hidden.
    spacer.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:spacer];
    [self.view addConstraints:[NSLayoutConstraint
        constraintsWithVisualFormat:@"|[spacer]|" options:0 metrics:nil
        views:NSDictionaryOfVariableBindings(spacer)]];
    return spacer;
}

要创建底部间隔符,我们将其固定到最后一个文本字段和超级视图。我们还将其高度限制为等于顶部间隔物的高度。

- (void)addSpacerFromBottomOfView:(UIView *)overView toTopOfView:(UIView *)underView {
    UIView *spacer = [self newSpacer];
    [self.view addConstraints:[NSLayoutConstraint
        constraintsWithVisualFormat:@"V:[overView][spacer(==topSpacer)][underView]" options:0 metrics:nil
        views:NSDictionaryOfVariableBindings(spacer, overView, underView, topSpacer)]];
}

如果你做对了,你会得到这样的结果:

example code screen shot

您可以在this github repository中找到完整的示例项目。

答案 1 :(得分:10)

结帐PureLayout。它被设计成最简单,程序最友好的API,可用于在代码中创建自动布局约束。

为了回答您的具体问题,PureLayout提供了两个用于分发视图的主要API,一个用于固定每个视图之间的间距(视图大小根据需要而变化),另一个用于固定每个视图的大小(间距)视图之间根据需要变化)。后者将完成您正在寻找的,而无需使用任何“间隔视图”。

// 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;

// ...

答案 2 :(得分:2)

请参阅developer.apple'文档,其中有关于解决方案的详细描述,https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html查看该页面中的间距和变形,我认为这是很好的描述,因此无需在此处解释相同的事情< / p>

修改

上面的链接现在被Apple禁用了。从iOS 9开始,他们引入了Stackview,这是所有这些的解决方案。

以前在上面的链接中答案与@rob

提供的答案相同