NSLayoutConstraint 的 Unsatisfiable Constraint 以编程方式更改 - swift
Posted
技术标签:
【中文标题】NSLayoutConstraint 的 Unsatisfiable Constraint 以编程方式更改 - swift【英文标题】:Unsatisfiable Constraint for NSLayoutConstraint changed programmatically - swift 【发布时间】:2020-10-04 10:02:05 【问题描述】:我在 viewDidLoad 中设置了一个约束,然后在键盘出现时更改它的常量。 这是初始设置
bottomConstraint = NSLayoutConstraint(item: bottomBar, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint)
然后我在收到键盘通知时更改常量:
@objc func handleKeyboardNotification(notification: NSNotification)
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification
bottomConstraint?.constant = isKeyboardShowing ? -keyboardHeight : 0
UIView.animate(withDuration:0.1, delay: 0 , options: .curveEaseOut , animations:
self.view.layoutIfNeeded()
, completion: (completed) in
)
这很有趣,因为我只是更改常量而不添加另一个约束。尽管如此,我还是在控制台中收到了这个警告:
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:0x282ae4ff0 UIView:0x109f11110.bottom == UIView:0x109f13240.bottom (active)>",
"<NSLayoutConstraint:0x282ae8050 UIView:0x109f11110.bottom == UIView:0x109f13240.bottom - 291 (active)>"
)
这基本上表明我的限制不能很好地协同工作。 我不知道我做错了什么。
编辑: 这是我用来以编程方式添加底栏的代码:
let bottomBar:UIView =
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
()
在 ViewdidLoad() 中
view.addSubview(bottomBar)
bottomBar.addSubview(fontView)
bottomBar.addSubview(colorPicker)
fontView.pin(to: bottomBar)
colorPicker.pin(to: bottomBar)
func setUpConstraints()
NSLayoutConstraint.activate([
bottomBar.leadingAnchor.constraint(equalTo: view.leadingAnchor),
bottomBar.trailingAnchor.constraint(equalTo: view.trailingAnchor),
bottomBar.heightAnchor.constraint(equalToConstant: 70),
])
【问题讨论】:
bottomBar.translatesAutoresizingMaskIntoConstraints
是真是假?
@Sweeper 是假的
您是否使用情节提要作为视图?
不,都是程序化创建的
@Stackgu 我认为@DonMag 指的是bottomViewConstraint
和bottomConstraint
是两个不同的变量。
【参考方案1】:
试图让你更轻松一些......
从简单开始。
这段代码在顶部附近创建了一个文本字段,并在底部创建了一个红色的“bottomBar”视图。当键盘显示或隐藏时,bottomBar 的底部约束常量会更新(点击视图上的任意位置以关闭键盘):
class ConstraintTestViewController: UIViewController
let bottomBar = UIView()
var bottomConstraint: NSLayoutConstraint!
override func viewDidLoad()
super.viewDidLoad()
// add a text field
let tf = UITextField()
tf.borderStyle = .roundedRect
tf.translatesAutoresizingMaskIntoConstraints = false
bottomBar.translatesAutoresizingMaskIntoConstraints = false
bottomBar.backgroundColor = .red
view.addSubview(tf)
view.addSubview(bottomBar)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain text field 80-pts from Top, Width: 240, centerX
tf.topAnchor.constraint(equalTo: g.topAnchor, constant: 80.0),
tf.widthAnchor.constraint(equalToConstant: 240.0),
tf.centerXAnchor.constraint(equalTo: g.centerXAnchor),
// constrain bottomBar Leading and Trailing, Height: 70-pts
bottomBar.leadingAnchor.constraint(equalTo: g.leadingAnchor),
bottomBar.trailingAnchor.constraint(equalTo: g.trailingAnchor),
bottomBar.heightAnchor.constraint(equalToConstant: 70.0),
])
// create and add the bottom constraint
bottomConstraint = NSLayoutConstraint(item: bottomBar, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint)
// or, use more modern syntax...
//bottomConstraint = bottomBar.bottomAnchor.constraint(equalTo: g.bottomAnchor)
//bottomConstraint.isActive = true
// keyboard show/hide notifications
NotificationCenter.default.addObserver(self,
selector: #selector(self.handleKeyboardNotification(notification:)),
name: UIResponder.keyboardWillShowNotification,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(self.handleKeyboardNotification(notification:)),
name: UIResponder.keyboardWillHideNotification,
object: nil)
// add a "tap on the view to dismiss the keyboard" gesture
let t = UITapGestureRecognizer(target: self, action: #selector(self.didTap(_:)))
view.addGestureRecognizer(t)
@objc func handleKeyboardNotification(notification: NSNotification)
if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue
let keyboardRectangle = keyboardFrame.cgRectValue
let keyboardHeight = keyboardRectangle.height
let isKeyboardShowing = notification.name == UIResponder.keyboardWillShowNotification
bottomConstraint.constant = isKeyboardShowing ? -keyboardHeight : 0
UIView.animate(withDuration:0.1, delay: 0 , options: .curveEaseOut , animations:
self.view.layoutIfNeeded()
, completion: (completed) in
)
@objc func didTap(_ g: UITapGestureRecognizer) -> Void
view.endEditing(true)
如果运行时没有自动布局错误/警告(它会),然后开始添加您的其他 UI 元素(和支持代码)一次一个 .如果/当你再次遇到约束冲突时,你就会确切地知道你哪里出错了。
【讨论】:
谢谢,我将从头开始,看看约束会发生什么以及底部约束导致错误的位置 我终于发现了它是什么,真是愚蠢的错误,我添加了两个用于初始化视图控制器的 sn-ps 代码:一个在 viewDidLoad 中(就像我习惯做的那样),另一个在自定义 init(nibName..),这导致创建双重约束。总之谢谢大家的支持!【参考方案2】:你没有提供足够的信息,所以有必要猜测。这是一个猜测。当你说:
fontView.pin(to: bottomBar)
colorPicker.pin(to: bottomBar)
您创建 两个 bottomBar
底部约束。当你说:
bottomConstraint = NSLayoutConstraint(item: bottomBar, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint)
你创建了一个第三个底部约束。
那么当你说
bottomConstraint?.constant = isKeyboardShowing ? -keyboardHeight : 0
您更改了一个底部约束,但没有更改其他约束。也许这就是冲突的原因。
另一种可能性是,您可能以某种未向我们展示的方式两次调用view.addConstraint
。同样,这意味着您正在更改一个底部约束,而不是另一个。
【讨论】:
感谢您的回答,我考虑了您的两个选项,但似乎它们都不适用于我的情况,我注意到每当我更改 bottomConstraint 的常量时都会出现警告(如果我在不更改常量的情况下设置它,它可以正常工作)所以我在想可能是因为无论何时显示或不显示通知都会被调用两次 通知可以多次调用。但这不是问题。这是两个不同的约束。您可以在错误消息中清楚地看到这一点。你需要相信它告诉你的东西。这不是系统错误。这是你的错误。相信我,除非你相信这一点,否则你不会明白这一点。有很多方法可以计算出你的约束是什么;使用它们。使用视图调试器。给出您的约束标识符(名称)。做任何事情来调试。 我终于发现了它是什么,真是愚蠢的错误,我添加了两个用于初始化视图控制器的 sn-ps 代码:一个在 viewDidLoad 中(就像我习惯做的那样),另一个在自定义 init(nibName..),这导致创建双重约束。总之谢谢大家的支持! 干得好。所以我的最后一段是对的!你在这里看到了课程的价值。相信运行时间!它说有两个约束,有有两个约束,就这么简单。以上是关于NSLayoutConstraint 的 Unsatisfiable Constraint 以编程方式更改 - swift的主要内容,如果未能解决你的问题,请参考以下文章