在视觉格式语言中给予视图相同的位置

Giving Views the same position in Visual Formatting Language

在视觉格式语言中有没有办法让两个元素在一个轴上保持相同的位置?

例如,我有一个 UILabel 和一个 UITextField,我希望它们水平并排放置。在布置垂直约束时是否有任何指定?

像这样的东西是理想的:

|-40-([label][field])-10-[otherStuff]

...其中 [label][field] 都具有相同的 Y 位置,但距离父视图顶部向下 40 点,在它们下方的 10 点是 [otherStuff]

这可能吗?

或者我应该将 [label][field] 嵌套在它们自己的 UIView 中,然后将其布局?

这样想:如果您可以在 Interface Builder 中使用自动布局来完成,那么您也可以使用可视化格式语言来完成。

但是,对于您建议的用例,您必须在多个语句中描述约束:

  1. 设置fieldlabel
  2. 水平方向相同
  3. 设置从父视图顶部到字段的垂直 space 40 像素,将 10 像素设置为 otherStuff

总体上需要的是,对于每个子视图,所有 4 个必要的放置值(x、y、宽度和高度)都已明确定义。

我通过代码实现自动布局的一般方法是编写一个自定义库,其方法与 Interface Builder 中的各个约束所做的相同。以下是一些示例方法签名:

  1. +(void)addFixedHeightConstraintToView:(UIView*)view height:(CGFloat)height;
  2. +(void)addTopMarginFromSuperviewConstraintToView:(UIView*)view topMargin:(CGFloat)topMargin;
  3. +(void)addHorizontalSpaceConstraintFromView:(UIView*)fromView toView:(UIView*)toView horizontalSpace:(CGFloat)hSpace;

这些方法都是用非常简单易懂的VFL定义的。一旦有了这些,我就可以轻松解决您描述的用例。这是一些示例代码:

[CustomAutoLayout addTopMarginFromSuperviewConstraintToView:field topMargin:40];
[CustomAutoLayout addTopMarginFromSuperviewConstraintToView:label topMargin:40];
[CustomAutoLayout addHorizontalSpaceConstraintFromView:field toView:label horizontalSpace:0];
[CustomAutoLayout addVerticalSpaceConstrantFromView:field toView:otherStuff verticalSpace:10];

我知道的唯一方法是两个使用 2 视觉格式语句,如下所示:

|-40-[label]-10-[otherStuff]
|-40-[field]

不幸的是,这意味着要重复第一个语句的一部分。

嵌套到另一个视图是一个解决方案。

您也可以在不使用可视格式语言的情况下在代码中添加约束:

NSLayoutConstraint* fieldLeft = [NSLayoutConstraint constraintWithItem:field
           attribute:NSLayoutConstraintAttributeLeading
           relatedBy:NSLayoutRelationEqual 
           toItem:label 
           multiplier:1 constant:0];
[field.superview addConstraint:fieldLeft];

视觉格式语言本身不支持这一点。首先,水平布局和垂直布局必须在两个单独的字符串中完成。但是 +[NSLayoutConstraint constraintsWithVisualFormat:options:metrics:views:] 接受可以包括对齐的选项。

因此,您可以使用:

NSDictionary* views = NSDictionaryOfVariableBindings(field, label);
NSArray* constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-40-[label]-10-[otherStuff]" options:0 metrics:nil views:views];
[field.superview addConstraints:constraints];
constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[label][field]" options:NSLayoutFormatAlignAllBaseline metrics:nil views:views];
[field.superview addConstraints:constraints];

在第二种情况下,NSLayoutFormatAlignAllBaseline 不仅使 field 落后于 label,而且它们处于相同的垂直位置(基于它们的基线,这可能比对齐它们的中心、顶部或底部更好。