I have spent several days on this with no solution in sight.
I have an inputAccessoryView
which consists of a UIView
containing a textView
and two buttons. The behaviour of the inputAccessoryView
is as expected and works fine in all cases except one.
When the height of the textView increases, I am trying to increase the height of the inputAccessoryView
by the same amount. When I redefine the height of the inputAccessoryView
in textViewDidChange
, the inputAccessoryView
increases height downwards over the keyboard instead of upwards.
I have tried many different suggestions from SO but nothing has worked. I guess it is the automatically added NSLayoutConstraint
of the inputAccessoryView
but I have no idea how to change that value in swift and iOS 8.3.
func textViewDidChange(textView: UITextView) {
var contentSize = messageTextView.sizeThatFits(CGSizeMake(messageTextView.frame.size.width, CGFloat.max))
inputAccessoryView.frame.size.height = contentSize.height + 16
}
adding
inputAccessoryView.setTranslatesAutoresizingMaskIntoConstraints(true)
to the above code helps and the inputAccessoryView height increases upwards correctly however I get Unable to simultaneously satisfy constraints for several constraints and it is very difficult to identify the offenders. Also I get an odd effect of the textView creating extra space below on every second instance of a new line.
thanks.
To make input accessory view grow vertically you just set its autoresizingMask = .flexibleHeight
, calculate its intrinsicContentSize
and let the framework do the rest.
The code:
class InputAccessoryView: UIView, UITextViewDelegate {
let textView = UITextView()
override init(frame: CGRect) {
super.init(frame: frame)
// This is required to make the view grow vertically
self.autoresizingMask = UIView.AutoresizingMask.flexibleHeight
// Setup textView as needed
self.addSubview(self.textView)
self.textView.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "H:|[textView]|", options: [], metrics: nil, views: ["textView": self.textView]))
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[textView]|", options: [], metrics: nil, views: ["textView": self.textView]))
self.textView.delegate = self
// Disabling textView scrolling prevents some undesired effects,
// like incorrect contentOffset when adding new line,
// and makes the textView behave similar to Apple's Messages app
self.textView.isScrollEnabled = false
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var intrinsicContentSize: CGSize {
// Calculate intrinsicContentSize that will fit all the text
let textSize = self.textView.sizeThatFits(CGSize(width: self.textView.bounds.width, height: CGFloat.greatestFiniteMagnitude))
return CGSize(width: self.bounds.width, height: textSize.height)
}
// MARK: UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
// Re-calculate intrinsicContentSize when text changes
self.invalidateIntrinsicContentSize()
}
}
Fast forward to 2020, you can just do the following, everything else the same as in maxkonovalov's answer
override var intrinsicContentSize: CGSize {
return .zero
}
// MARK: UITextViewDelegate
func textViewDidChange(_ textView: UITextView) {
sizeToFit()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With