使用視覺格式語言
有一種方法可以簡化使用 VFL 定義檢視的自動佈局。起初看起來似乎很難,但它實際上很容易使用。一些定義首先:
|
代表 superviewH:
或V:
代表當前方向 - 水平或垂直- 檢視名稱應括在方括號中
- 檢視的高度和寬度應括在括號中
- 邊距在檢視之間指定並由連字元包圍
- 可以使用 @指定邊距或檢視大小的優先順序
可視格式語法的示例
-
someView
附加到其超檢視的左右邊緣,沒有邊距:H:|[someView]|
-
someView
附在頂部,邊緣為 10 個點,高度等於value
:V:|-(10)-[someView(value)]
-
someView1
和someView2
之間定義了兩個邊距 -value1
優先順序為 900,value2
優先順序為 800:H:[someView1]-(value1@900, value2@800)-[someView2]
-
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]];
}