I'm setting up a constraint in viewDidLoad and then changing its constant when the keyboard shows up. This is the initial set Up
bottomConstraint = NSLayoutConstraint(item: bottomBar, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
view.addConstraint(bottomConstraint)
Then I change the constant when I receive a keyboard notification:
@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
})
}
}
It's interesting because I'm only changing the constant and not adding another constraint. Nevertheless I receive this warning in console:
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)>"
)
Which basically states that the constraints I have don't work well togheter. I don't know what I'm doing wrong.
EDIT: This is the code I use to add the bottom bar programmatically:
let bottomBar:UIView = {
let v = UIView()
v.translatesAutoresizingMaskIntoConstraints = false
return v
}()
In 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),
])
}
Attempting to make it a bit easier for you...
Start simple.
This code creates a text field near the top, and a red "bottomBar" view at the bottom. When the keyboard shows or hides, the bottomBar's bottom constraint constant is updated (tap anywhere on the view to dismiss the keyboard):
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)
}
}
If this runs without auto-layout errors / warnings (which it will), then start adding in your other UI elements (and supporting code) one at a time. If / when you get the constraint conflict again, you'll know exactly where you went wrong.