安全地更改 NSLayoutConstraint 常量值

Safely change NSLayoutConstraint constant value

我的 UIView 对象有底部约束,我想更改它的值。在我这样做之后,视图确实显示正确,但是,我在控制台中看到错误日志;

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600003cbe670 PSBApp.KeyboardView:0x7fc5f760e010.bottom == UIView:0x7fc5f4503090.bottom + 306   (active)>",
    "<NSLayoutConstraint:0x600003c8cbe0 PSBApp.KeyboardView:0x7fc5f760e010.bottom == UIView:0x7fc5f4503090.bottom - 10   (active)>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600003cbe670 PSBApp.KeyboardView:0x7fc5f760e010.bottom == UIView:0x7fc5f4503090.bottom + 306   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.

我的代码是:

private func setupKeyboard(){
    keyboard.delegate = self
    view.addSubview(keyboard)
    keyboardBottomConstraint = keyboard.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: keyboard.expectedHeight())
    keyboard.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
    keyboardBottomConstraint.isActive = true
  }

  private func showKeyboard(){
    let bottomOffset: CGFloat = 10
    keyboardBottomConstraint.constant = -bottomOffset
  }

所以,在我 setupKeyboard 之后没有错误,屏幕上也没有可见的视图,然后,在我调用 showKeyboard 之后它变得可见,但是出现错误。

将底部约束优先级值设置为高(750)

您可以自动使用 layoutIfNeeded 和 setNeedsLayout:

layoutIfNeeded 强制接收器在需要时立即布局其子视图。

假设您已经覆盖了 layoutSubviews,并且 UIKit 认为您的视图出于某种原因需要布局(例如,您在处理某些用户操作时调用了 setNeedsLayout)。然后,您的自定义 layoutSubviews 方法将立即被调用,而不是在常规 UIKit 运行 循环事件序列中通常被调用时被调用(在事件处理之后,但在 drawRect: 之前)。

您可能需要在单个 运行 循环中调用 layoutIfNeeded 的示例:

您调整了自定义视图的大小,其中包含具有自定义布局的 table 视图。设置 setNeedsLayout 以便稍后调用 layoutSubviews。 控制器对象要求 table 视图在处理用户事件时滚动到某个特定的单元格。 您的自定义视图对 layoutSubviews 中的 table 视图执行一些自定义大小调整,从而更改 table 视图大小。 问题是当控制器要求 table 视图滚动(第 2 步)时,table 视图的边界是陈旧的。更新后的边界只会在稍后(第 3 步)的 table 视图上设置。在 layoutSubviews 完成后,控制器希望 table 视图滚动到的内容可能实际上不可见。一个解决方案是让控制器在知道可能发生这种情况的情况下调用 layoutIfNeeded。

有错误/警告消息是关键:

(
    "<NSLayoutConstraint:0x600003cbe670 PSBApp.KeyboardView:0x7fc5f760e010.bottom == UIView:0x7fc5f4503090.bottom + 306   (active)>",
    "<NSLayoutConstraint:0x600003c8cbe0 PSBApp.KeyboardView:0x7fc5f760e010.bottom == UIView:0x7fc5f4503090.bottom - 10   (active)>"
)

如您所见,KeyboardView 两个 底部约束,它们不能同时有效。

根据 OP 的评论,setupKeyboard() 被无意中调用了两次,导致 2 个底部约束。