autolayout自动布局入门


备注

自动布局根据Apple对这些视图的限制,动态计算视图层次结构中所有视图的大小和位置。通过将自动布局描述为用于视图层次结构中每个视图的一组规则,也可以理解自动布局,该规则定义了如何根据设备的不同屏幕尺寸执行视图的对齐和缩小或扩展。

我们应该在所有项目中使用自动布局,因为这有助于我们管理所有可用设备的屏幕设计。为此,我们只需要了解它是什么以及它的表现如何,在我们了解它的工作原理后,为多个设备设计动态布局将会很有趣。

将UIImageView添加到屏幕中心

如果要将UIImageView添加到屏幕中心,宽度和高度为100像素,则需要将中心x约束和中心y约束设置为从UIImageView和宽度,高度约束到UIIMageView的超视图。这是代码。有可能在故事板中这样做,但我已经用代码编写,因为它可以理解文档中的这种情况。

UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 100.0, 100.0);
imageView.self.translatesAutoresizingMaskIntoConstraints = NO;

[imageView addConstraint:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:100.0]];
[imageView addConstraint:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:100.0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
[superview addConstraint:[NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:superview attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];
 

安装或设置

要使用自动布局,我们需要在storyboard中启用布尔标志。它显示在下图中。在此之后,我们可以在故事板中使用自动布局。如果我们想要使用大小类,还有另一种选择。大小等级在自动布局中也是一个有用的选项,它有助于我们针对不同的设备屏幕尺寸设计不同的相同或不同的元素。设置的图像在这里。它来自Xcode中属性编辑器的文件检查器面板。

在此处输入图像描述

使用视觉格式语言

有一种方法可以简化使用VFL定义视图的自动布局。起初看起来似乎很难,但它实际上很容易使用。一些定义首先:

  • | 代表超级视图
  • H:V: 表示当前方向 - 水平或垂直
  • 视图名称应括在方括号中
  • 视图的高度和宽度应括在括号中
  • 边距在视图之间指定并由连字符包围
  • 可以使用@指定边距或视图大小的优先级

可视格式语法的示例

  1. someView 附加到其someView 左右边缘,没有边距:

    H:|[someView]|
     
  2. someView 附加到顶部,边距为10点,高度等于value

    V:|-(10)-[someView(value)]
     
  3. someView1someView2 之间定义了两个边距 - value1 优先级为900, value2 优先级为800:

    H:[someView1]-(value1@900, value2@800)-[someView2]
     
  4. someView1 高度等于高度someView2

    V:[someView1(==someView2)]
     

代码示例

自定义视图示例

让我们定义一个新视图,它有一个文本字段和两个高度相等的按钮,它们之间有边距,下面有一个标签。按钮应具有相等的宽度,如果内容足够长,标签应溢出到下一行。此视图应根据其在水平和垂直轴上的内容自动调整大小,并在其超视图的中间居中。

- (void)addView {

    // first lets define a container for our views
    UIView *container = [UIView new];
    // do not forget to disable autoresizing masks for autolayout views
    container.translatesAutoresizingMaskIntoConstraints = NO;
    container.backgroundColor = [UIColor grayColor];
    
    // now to the subviews. this is mostly boilerplate code:
    UITextField *textField = [UITextField new];
    textField.translatesAutoresizingMaskIntoConstraints = NO;
    textField.borderStyle = UITextBorderStyleRoundedRect;

    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeSystem];
    button1.translatesAutoresizingMaskIntoConstraints = NO;
    [button1 setTitle:@"Send" forState:UIControlStateNormal];

    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeSystem];
    button2.translatesAutoresizingMaskIntoConstraints = NO;
    [button2 setTitle:@"Cancel" forState:UIControlStateNormal];

    UILabel *label = [UILabel new];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    // this line tells the label to let the text overflow to the next line if needed
    label.numberOfLines = 0;
    label.text = @"This label has relatively long text, that should take two lines.";
    
    // before adding any constraints the views should be present in the hierarchy
    [container addSubview:textField];
    [container addSubview:button1];
    [container addSubview:button2];
    [container addSubview:label];
    
    // now lets define two helper dictionaries, one for metrics of our view:
    NSDictionary *metrics = @{@"margin": @10, @"textFieldWidth": @160, @"buttonWidth": @44};
    // and the other for view bindings using a handy macro, which effectively creates a dictionary with variables of the same name:
    NSDictionary *bindings = NSDictionaryOfVariableBindings(textField, button1, button2, label);
    // lets define a horizontal format for the first row of views in a variable:
    NSString *horizontalFormat = @"H:|-(margin)-[textField(textFieldWidth)]-(margin)-[button1(==button2)]-(margin)-[button2]-(margin)-|";
    // this format defines margins of equal size between all views, fixed width for the textField and sets both buttons to have equal widths
    // lets add these constraints to our container:
    [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:horizontalFormat options:0 metrics:metrics views:bindings]];
    // now lets define horizontal constraints for the second row, where we have the label:
    [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(margin)-[label]-(margin)-|" options:0 metrics:metrics views:bindings]];
    // another relatively long visual format string:
    NSString *verticalFormat = @"V:|-(margin)-[textField]-(margin)-[label]-(margin)-|";
    // this format string defines vertical constraints for textField and label, and should also define the height of the container
    // adding these constraints to the container view:
    [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:verticalFormat options:0 metrics:metrics views:bindings]];
    // what we have left are constraints for vertical positions of the buttons
    // lets attach them to the top of the container with a margin:
    [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(margin)-[button1]" options:0 metrics:metrics views:bindings]];
    [container addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(margin)-[button2]" options:0 metrics:metrics views:bindings]];
    
    // the container is all set up, adding it to the superview:
    [self.view addSubview:container];
    
    // now lets position our container in its superview
    // you can not use dot notation in the bindings macro, so lets define a temp variable for the superview:
    UIView *superview = self.view;
    
    // positioning a view in the center of its superview is not so straightforward
    // we will use a trick from this answer: http://stackoverflow.com/a/14917695/934710
    NSDictionary *containerBindings = NSDictionaryOfVariableBindings(superview, container);
    // width constraint from horizontal format is not part of the trick, but is necessary to constrain container width
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[superview]-(<=1)-[container(<=superview)]" options:NSLayoutFormatAlignAllCenterY metrics:nil views:containerBindings]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[superview]-(<=1)-[container]" options:NSLayoutFormatAlignAllCenterX metrics:nil views:containerBindings]];

}