So I'm making a messaging app, and I have 4 class properties:
typingView: UIView!messageTextView: UITextView!sendButton: UIButton!typingViewHeight: NSLayoutConstraint?
The typingView is the inputAccessoryView of the main view, which works! It contains the messageTextView and sendButton. But my problem is...when the number of lines of text in the messageTextView increases, I want the height to increase with an animation (I'm ignoring decreasing for now). And by doing that, I decided to change the height of the typingView.
Detecting a change in contentSize works perfectly, I added an observer by adding this line
messageTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
and listened to it with this override
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
Inside of this function, I have (this is an over simplification and pseudocode, just assume it works)
UIView.animate(withDuration: keyboardAnimationDuration) {
self.typingViewHeight?.constaint += (messageTextView.font?.lineHeight)!
}
Here is my code for the customizing the inputAccessoryView:
lazy var typingViewContainer: UIView = {
// Set up typing view
typingView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: 55))
typingView.backgroundColor = UIColor.darkGray
typingView.translatesAutoresizingMaskIntoConstraints = false
// Set up animated constraints
typingViewHeight = typingView.heightAnchor.constraint(equalToConstant: typingView.frame.height)
typingViewHeight?.isActive = true
// Set up text view
messageTextView = UITextView()
messageTextView.translatesAutoresizingMaskIntoConstraints = false
messageTextView.font = fakeMessageTextView.font
messageTextView.keyboardType = fakeMessageTextView.keyboardType
messageTextView.isScrollEnabled = fakeMessageTextView.isScrollEnabled
messageTextView.alwaysBounceVertical = fakeMessageTextView.alwaysBounceVertical
messageTextView.text = fakeMessageTextView.text
messageTextView.textColor = fakeMessageTextView.textColor
messageTextView.delegate = self
typingView.addSubview(messageTextView)
// Constraints
messageTextView.bottomAnchor.constraint(equalTo: typingView.bottomAnchor, constant: -fakeMessageTextViewBottom.constant).isActive = true
messageTextView.topAnchor.constraint(equalTo: typingView.topAnchor, constant: fakeMessageTextViewTop.constant).isActive = true
messageTextView.leftAnchor.constraint(equalTo: typingView.leftAnchor, constant: fakeMessageTextViewBottom.constant).isActive = true
messageTextView.widthAnchor.constraint(equalToConstant: fakeMessageTextViewWidth.constant).isActive = true
// Observers
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
messageTextView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil)
// Set up send button
sendButton = UIButton(type: fakeSendButton.buttonType)
sendButton.translatesAutoresizingMaskIntoConstraints = false
sendButton.setTitle(fakeSendButton.titleLabel?.text!, for: .normal)
sendButton.titleLabel?.font = fakeSendButton.titleLabel?.font
sendButton.titleLabel?.shadowColor = fakeSendButton.titleLabel?.shadowColor
sendButton.addTarget(self, action: #selector(sendPressed(_:)), for: .touchUpInside)
typingView.addSubview(sendButton)
// Constraints
sendButton.heightAnchor.constraint(equalToConstant: fakeSendButtonHeight.constant).isActive = true
sendButton.widthAnchor.constraint(equalToConstant: fakeSendButtonWidth.constant).isActive = true
sendButton.bottomAnchor.constraint(equalTo: typingView.bottomAnchor, constant: -fakeSendButtonBottom.constant).isActive = true
sendButton.rightAnchor.constraint(equalTo: typingView.rightAnchor, constant: -fakeSendButtonRight.constant).isActive = true
return typingView
}()
override var inputAccessoryView: UIView? {
get {
return typingViewContainer
}
}
override var canBecomeFirstResponder: Bool {
get {
return true
}
}
But when I test this and typing in multiple lines, it prints out this in the console:
2018-04-25 08:52:57.614383-0500 ProxiChat[3351:168967] [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:0x608000280a50 UIView:0x7f8528a2cda0.height == 73 (active)>",
"<NSLayoutConstraint:0x6040000993c0 UIView:0x7f8528a2cda0.height == 55 (active)>"
)
Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x608000280a50 UIView:0x7f8528a2cda0.height == 73
(active)>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
Why are there two constraints? I only added one. Please help, thanks!
EDIT
Assume that my code for changing the height of the typingView works, since it worked before I changed my view to be a custom inputAccessoryView. I just want to know why it's printing out that error, and how I can fix it from setting two constraints, even though I only added one?