NSLayoutConstraint 的不可满足约束以编程方式更改 - swift
Unsatisfiable Constraint for NSLayoutConstraint changed programmatically - swift
我在 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),
])
}
您提供的信息不够,所以需要猜测。这是一个猜测。当你说:
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
两次,但您并未向我们展示。同样,这意味着您正在更改一个底部约束而不是另一个。
正在尝试让您更轻松一些...
从简单开始。
此代码在顶部附近创建一个文本字段,并在底部创建一个红色的“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)
}
}
如果运行时没有 auto-layout 错误/警告(它会),然后开始添加其他 UI 元素(和支持代码)一次一个。如果/当你再次遇到约束冲突的时候,你就知道哪里错了。
我在 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),
])
}
您提供的信息不够,所以需要猜测。这是一个猜测。当你说:
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
两次,但您并未向我们展示。同样,这意味着您正在更改一个底部约束而不是另一个。
正在尝试让您更轻松一些...
从简单开始。
此代码在顶部附近创建一个文本字段,并在底部创建一个红色的“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)
}
}
如果运行时没有 auto-layout 错误/警告(它会),然后开始添加其他 UI 元素(和支持代码)一次一个。如果/当你再次遇到约束冲突的时候,你就知道哪里错了。