I have this UITextView & I want it's height to change dynamically when the user is typing on it. I want to do it programmatically. I have the UITextView above another UIView. The constraints are set as below:
addtextview.leadingAnchor.constraint(equalTo: addtasktextview.leadingAnchor, constant: 8).isActive = true
addtextview.trailingAnchor.constraint(equalTo: addtasktextview.trailingAnchor, constant: -8).isActive = true
addtextview.topAnchor.constraint(equalTo: addtasktextview.topAnchor, constant: 8).isActive = true
addtextview.bottomAnchor.constraint(equalTo: addtasktextview.bottomAnchor, constant: -40).isActive = true
Interestingly enough, I am using textview in tableViewCells as well and dynamically changing the height by using just this constraint method, but over here it is not working. I want the textview's height to increase in such a way that it moves upward. So when a new line starts, the top part should move maintaining the spacing below.
How can I do it? Help will be appreciated it.
UPDATE: I was able to get it working with @upholder-of-truth 's answer below. I was also able to dynamically change the parent UIView container height by finding the difference between the textview normal height and the newSize.height and then adding that difference to the container's height.
First make sure your class adopts the UITextViewDelegate protocol so you can be informed when the text changes like this:
class MyClass: UIViewContoller, UITextViewDelegate
Next define this variable somewhere in your class so that you can keep track of the height in a constraint:
var textHeightConstraint: NSLayoutConstraint!
Next add the following constraint and activate it:
self.textHeightConstraint = addtextview.heightAnchor.constraint(equalToConstant: 40)
self.textHeightConstraint.isActive = true
(if you don't do this in viewDidLoad you need to make textHeightConstraint an optional)
Next subscribe to the delegate (if not already done):
addTextView.delegate = self
Add this function which recalculates the height constraint:
func adjustTextViewHeight() {
let fixedWidth = addtextview.frame.size.width
let newSize = addtextview.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
self.textHeightConstraint.constant = newSize.height
self.view.layoutIfNeeded()
}
Next add a call to that function after the constraints are created to set the initial size:
self.adjustTextViewHeight()
Finally add this method to adjust the height whenever the text changes:
func textViewDidChange(_ textView: UITextView) {
self.adjustTextViewHeight()
}
Just in case that is all confusing here is a minimal example in a sub class of a UIViewController:
class ViewController: UIViewController, UITextViewDelegate {
@IBOutlet var textView: UITextView!
@IBOutlet var textHolder: UIView!
var textHeightConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
textView.leadingAnchor.constraint(equalTo: textHolder.leadingAnchor, constant: 8).isActive = true
textView.trailingAnchor.constraint(equalTo: textHolder.trailingAnchor, constant: -8).isActive = true
textView.topAnchor.constraint(equalTo: textHolder.topAnchor, constant: 8).isActive = true
textView.bottomAnchor.constraint(equalTo: textHolder.bottomAnchor, constant: -40).isActive = true
self.textHeightConstraint = textView.heightAnchor.constraint(equalToConstant: 40)
self.textHeightConstraint.isActive = true
self.adjustTextViewHeight()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textViewDidChange(_ textView: UITextView) {
self.adjustTextViewHeight()
}
func adjustTextViewHeight() {
let fixedWidth = textView.frame.size.width
let newSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
self.textHeightConstraint.constant = newSize.height
self.view.layoutIfNeeded()
}
}