如何在使用自动布局的代码中设置UIView之间的标准间距?

6
在界面构建器中,我可以通过“固定”来获取与“标准”间距相匹配的“垂直间距”:

enter image description hereenter image description here

在可视化约束语言中,我可以通过以下方式实现相同的效果:
V:[top]-[bottom]

我该如何在代码中为两个视图添加标准间距?

我正在寻找类似于UIViewController中可能出现的以下内容:

NSLayoutConstraint *spacing = ???
[self.view addConstraint spacing];

为什么不能在代码中使用可视化格式,或者这只是一个好奇的问题(对我来说没关系!) - jrturton
@jrturton,我所有的其他限制都在代码中。我这样做是因为我在文档中发现了这个语句:“有些约束无法用可视格式语法表达,尽管大多数在实际用户界面中有用的约束都可以。一个有用的约束是无法表达固定的纵横比(例如,imageView.width = 2 * imageView.height)。 ”在我知道自己在做什么以及所有可视语言的限制变得清晰之前,我想先在代码中完成所有操作。 - Rich Apodaca
3个回答

6
自 iOS 11.0(于2017年发布)起,有使用系统间距的方法:
@interface NSLayoutXAxisAnchor (UIViewDynamicSystemSpacingSupport)
/* Constraints of the form,
 receiver [= | ≥ | ≤] 'anchor' + 'multiplier' * system space, 
 where the value of the system space is determined from information available from the anchors.
 The constraint affects how far the receiver will be positioned trailing 'anchor', per the effective user interface layout direction.
 */
- (NSLayoutConstraint *)constraintEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintLessThanOrEqualToSystemSpacingAfterAnchor:(NSLayoutXAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));

@end

@interface NSLayoutYAxisAnchor (UIViewDynamicSystemSpacingSupport)
/* Constraints of the form,
 receiver [= | ≥ | ≤] 'anchor' + 'multiplier' * system space, 
 where the value of the system space is determined from information available from the anchors.
 The constraint affects how far the receiver will be positioned below 'anchor'. 
 If either the receiver or 'anchor' is the firstBaselineAnchor or lastBaselineAnchor of a view with text content
 then the spacing will depend on the fonts involved and will change when those do.
 */
- (NSLayoutConstraint *)constraintEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintGreaterThanOrEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));
- (NSLayoutConstraint *)constraintLessThanOrEqualToSystemSpacingBelowAnchor:(NSLayoutYAxisAnchor *)anchor multiplier:(CGFloat)multiplier __attribute__((warn_unused_result)) API_AVAILABLE(macos(11.0),ios(11.0),tvos(11.0));
@end

在Swift中,你可以这样使用它们:
let topView: UIView = ...
let bottomView: UIView = ...

bottomView.topAnchor
    .constraint(equalToSystemSpacingBelow: topView.bottomAnchor, multiplier: 1)
    .isActive = true

let leadingView: UIView = ...
let trailingView: UIView = ...

trailingView.leadingAnchor
    .constraint(equalToSystemSpacingAfter: leadingView.trailingAnchor, multiplier: 1)
    .isActive = true

5
这不就是硬编码一个长度为8的空格吗?我想OP是在寻找一些系统常量或关键字来描述标准间距。 - jrturton
@jrturton 我在头文件中找不到它的常量。 - rob mayoff
@jrturton,如果有一个系统常量可以表示标准间距,那将是一个不错的选择。但我宁愿不直接使用数字8。 - Rich Apodaca
@robmayoff 我也不行。说到自动布局,我真的很感激您对 https://dev59.com/x2cs5IYBdhLWcg3wUCYI 的意见,这似乎涉及到了您的几个专业领域? - jrturton

2
混合使用视觉格式约束和更冗长的单个约束创建样式(当您说“在代码中”时,我认为您指的是这种样式)是可以的 - 实际上,在有关自动布局的WWDC演讲中,您创建约束的“首选”顺序被说明为:
  • 界面构建器
  • 视觉格式
  • 单个约束样式
除非您需要单个约束样式提供的额外功能和灵活性(在我迄今使用它的经验中,有很多地方视觉格式无法解决),否则应该使用视觉格式。听起来您是从下往上逐步接近上面的列表,而不是从上往下。
如果您想使用标准间距布置视图,并且没有使用IB,则使用视觉格式是有意义的。正如Rob所说,“标准”间距没有可用的常量,如果坚持为每个约束使用单个约束,则会增加更多的工作量。

我最终采用了混合视觉格式样式,只有一个例外 - 相对大小约束无法用其他方式表达,只能用代码表示。这大大简化了约束代码。做得好。 - Rich Apodaca

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接