在文本字段成为第一响应者(获得键盘)之前,在第一个基线与 UITextField 对齐的 UILabel 不起作用

UILabel aligned with UITextField at first baseline does not work until the textfield becomes first responder (got Keyboard)

我在各种不同的设置中都遇到过这个问题,包括使用 IB 和手动定义约束时。这是当前设置:

我在使用以下视觉格式约束的容器视图中有一个标签和一个文本字段:

H:|-(4)-[label(labelWidth)]-(4)-[editor]-(4)-|
option = NSLayoutFormatAlignAllFirstBaseline

V:|-(4)-[editor]-(4)-|

对于这些约束,标签位于屏幕 top-left 角的容器视图外(实际上在导航栏下方)。

当我添加这些约束时:

V:|-(>=4)-[label]-(>=4)-|

标签距顶部 4pt(匹配新约束)。

在这两种情况下,一旦我点击文本字段打开键盘然后再次关闭它(无需更改即可发生这种情况),标签会正确地与文本字段基线对齐。

[编辑:添加了一些屏幕截图] 初始状态:

键盘打开:

键盘关闭后正确显示:

在 Xcode 调试器中,基线约束在键盘打开和关闭之前显示为不活动,在键盘打开和关闭之后显示为活动。

似乎直到第一次编辑之后才(正确)计算文本字段的基线。使用 nil、@"" 或某些文本初始化文本字段不会影响行为。

问题是,是什么导致了这种行为,更重要的是,我该怎么办?

如果文本字段是以编程方式创建的,或者如果 IB 未添加基线对齐约束,则文本字段基线视图未正确定位。

在正确的时间调用 [textField setNeedsUpdateConstraints](见下文)解决了这个问题。

在我的例子中,我有一个自定义容器视图,adds/replaces 约束布局标签和文本字段。我不得不在容器视图的 layoutSubviews 方法中调用 [textField setNeedsUpdateConstraints]。在修改约束的 updateConstraints 中调用它没有帮助。

在文本字段已经有基线对齐(与任何视图、标签或另一个)将被新基线对齐替换的类似情况下,问题不会发生,显然是因为 IB 会以某种方式注意及时布局参与的文本字段。

所以我的 workaround/solution 是:

- (void)updateConstraints {
  // setup constraints for affected views in self.viewsDictionary
  [super updateConstraints];
}

- (void)layoutSubviews {
  [super layoutSubviews];
  for (UIView* view in self.viewDictionary.objectEnumerator) {
    [view setNeedsUpdateConstraints];
  }
}