Reputation: 638
I'm trying to create a particular textfield. As any chat application you have a textfield where you can write your message and send it. This field increase its height to 3 lines of text before it becomes scrollable.
In my case, the textfield is made like that :
In orange it is the textfield zone, on the right you can see the sending button with an image view in it. All these elements are included in a view that you can see around the textfield.
The only height constraint is put on the textfield.
To adapt the height of the textfield to the height of its content I'm using the following code :
func textViewDidChange(textView: UITextView)
{
contentSize = textField.contentSize.height
if(previousContentSize != contentSize)
{
//textField.sizeThatFits(CGSize(width: view.bounds.width - 55, height: 0))
heightTextfieldConstraint.constant = textField.contentSize.height
}
previousContentSize = contentSize
}
And this function is called in every change in the textfield.
It works, but in a strange way. Indeed when there is the second line return the text appears like that :
And then when there is the third line return :
Why the contentInset Top is not good when there is the second line and is good when there is the third one ?
I've tried to use sizeToFit()
but I didn't have any good result.
Upvotes: 0
Views: 138
Reputation: 2478
I get in to the exact same trouble a while ago. And here is the workaround coming from this blog post written by Adam Siton.
The idea is to update contentOffset after frame changes to center text correctly. Here is the workaround example.
final class AutoGrowingTextView: UITextView {
@IBInspectable var minHeight: CGFloat = 20
@IBInspectable var maxHeight: CGFloat = 90
var heightConstraint: NSLayoutConstraint!
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
override func awakeFromNib() {
super.awakeFromNib()
setup()
}
override func layoutSubviews() {
super.layoutSubviews()
handleAutoLayouts()
centerVertically()
}
private func handleAutoLayouts() {
var intrinsicSize = self.intrinsicContentSize()
intrinsicSize.height = max(intrinsicSize.height, minHeight);
intrinsicSize.height = min(intrinsicSize.height, maxHeight);
heightConstraint.constant = intrinsicSize.height
}
private func centerVertically() {
// We're supposed to have a maximum height contstarint in code for the text view which will makes the intrinsicSide eventually higher then the height of the text view - if we had enough text.
// This code only center vertically the text view while the context size is smaller/equal to the text view frame.
if intrinsicContentSize().height <= self.bounds.size.height {
var topCorrect = (self.bounds.size.height - self.contentSize.height * zoomScale) / 2
topCorrect = ( topCorrect < 0.0 ? 0.0 : topCorrect )
self.contentOffset = CGPointMake(0, -topCorrect)
}
}
override func intrinsicContentSize() -> CGSize {
var intrinsicContentSize = self.contentSize
intrinsicContentSize.width += (textContainerInset.left + textContainerInset.right ) / 2
intrinsicContentSize.height += (textContainerInset.top + textContainerInset.bottom) / 2
return intrinsicContentSize
}
private func setup() {
for const in constraints {
if const.firstAttribute == .Height {
heightConstraint = const
break
}
}
}
}
Upvotes: 1