iOS Autolayout 垂直相等的空间来填充父视图 [英] iOS Autolayout Vertically equal space to fill parent view

查看:15
本文介绍了iOS Autolayout 垂直相等的空间来填充父视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有 12 个 UITextFields 的视图控制器.

I have a view controller with 12 UITextFields.

它非常适合 3.5" 显示器.

It fits a 3.5" display very well.

我需要为 iPhone 5(4 英寸显示器)设置它,以便所有 UITextField 覆盖整个 UIView,方法是在它们之间添加额外的空间.

I need to set it for iPhone 5 (4 inch display) such that all UITextFields cover the whole UIView by adding extra space in between.

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

I am trying to do this by auto layout but it is not working properly.

这是我的代码:

- (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" 屏幕相同的内容并在下方留出空间.

If I do [txt12(==txt1)] then it displays the same as the 3.5" screen and leaves space below.

我哪里出错了?

推荐答案

要使用自动布局做到这一点,您必须创建额外的视图来填充文本字段之间的空间.

To do this with auto layout, you must create extra views to fill the spaces between the text fields.

回想一下,自动布局约束基本上是线性方程A = m * B + c.A 是一个视图的属性(例如,viewA 底边的 Y 坐标),B 是另一个视图的属性(例如,viewB 的上边缘的 Y 坐标).mc 是常量.因此,例如,布置 viewAviewB 以便在 viewA 的底部和 的顶部之间有 30 个点viewB,我们可以创建一个约束,其中 m 为 1,c 为 -30.

Recall that an auto layout constraint is basically the linear equation A = m * B + c. A is an attribute of one view (for example, the Y coordinate of viewA's bottom edge) and B is an attribute of another view (for example, the Y coordinate of viewB's top edge). m and c are constants. So, for example, to lay out viewA and viewB so that there are 30 points between the bottom of viewA and the top of viewB, we could create a constraint where m is 1 and c is -30.

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

The problem you're having is that you want to use the same value for c across 13 different constraints, and you want auto layout to compute that c value for you. Auto layout simply can't do that. Not directly. Auto layout can only compute the attributes of views; it cannot compute the m and c constants.

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

There is a way to make auto layout put the views where you want: reify the spaces between the text fields as additional (invisible) views. Here's an example with just 3 text fields:

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

We'll create a constraint to pin each spacer's top edge to the bottom edge of the text field above it. We'll also create a constraint to pin each spacer's bottom edge to the top edge of the text field below it. And finally, we'll create a constraint to force each spacer to have the same height as the topmost spacer.

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

We'll need a two instance variables to set things up: an array of the text fields (in order from top to bottom), and a reference to the topmost spacer view:

@implementation ViewController {
    NSMutableArray *textFields;
    UIView *topSpacer;
}

我们将在代码中创建文本字段和分隔符,因为在 stackoverflow 答案中很难显示 xib.我们在 viewDidLoad 中开始:

We'll create the text fields and spacers in code since it's hard to show a xib in a stackoverflow answer. We kick things off in viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.translatesAutoresizingMaskIntoConstraints = NO;
    [self addTextFields];
    [self addSpacers];
}

由于我们要使用自动布局,我们需要关闭 translatesAutoresizingMaskIntoConstraints 以防止系统创建额外的约束.

Since we're going to use auto layout, we need to turn off translatesAutoresizingMaskIntoConstraints to prevent the system from creating extra constraints.

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

We create each text field, give it some dummy text, and set up constraints for its horizontal position and size:

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

我们也将使用循环来创建垫片,但我们创建顶部和底部垫片与中间垫片不同,因为我们需要将顶部和底部垫片固定到超级视图:

We'll use a loop to create the spacers too, but we create the top and bottom spacers differently from the middle spacers, because we need to pin the top and bottom spacers to the 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 中,因此我们可以约束其他垫片与顶部垫片具有相同的高度.

Here's how we create the top spacer and set up its constraints. Its top edge is pinned to the superview and its bottom edge is pinned to the first (topmost) text field. We store the top spacer in the instance variable topSpacer so we can constrain the other spacers to have the same height as the top spacer.

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

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

Here's how we actually create a spacer view. It's just a hidden view. Since we don't care about its horizontal size or position, we just pin it to the left and right edges of the superview.

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

为了在两个文本视图之间创建一个中间"间隔,我们将它固定到文本的底部边缘上方的字段和下方文本字段的上边缘.我们还将其高度限制为与顶部垫片的高度相同.

To create a "middle" spacer between two text views, we pin it to the bottom edge of the text field above and the top edge of the text field below. We also constrain its height to equal the height of the top 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)]];
}

要创建底部间隔,我们将其固定到最后一个文本字段和超级视图.我们还将其高度限制为与顶部垫片的高度相同.

To create the bottom spacer, we pin it to the last text field and to the superview. We also constrain its height to equal the height of the top spacer.

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

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

If you do it right, you will get a result like this:

您可以在 这个 github 存储库.

这篇关于iOS Autolayout 垂直相等的空间来填充父视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆