Resizing UITextView does not work correctly on first 2 characters of a new line

1.9k Views Asked by At

I have a UITextView called messageTextView, that is a subview of a UIView that I call messageFieldContainer.

I need to resize both my UITextView and the container UIView as the user types in more characters into the UITextView.

Here is the current method that I am using to accomplish this:

- (void)textViewDidChange:(UITextView *)textView
{
    CGFloat fixedWidth = textView.frame.size.width;
    CGSize newSize = [textView sizeThatFits:CGSizeMake(fixedWidth, CGFLOAT_MAX)];
    CGRect newFrame = textView.frame;
    newFrame.size = CGSizeMake(fmaxf(newSize.width, fixedWidth), newSize.height);

    if (self.previousFrameSize.height && self.previousFrameSize.height != newFrame.size.height) {
        self.messageFieldContainer.frame = CGRectMake(0, self.messageFieldContainer.frame.origin.y - 20, self.messageFieldContainer.bounds.size.width, newFrame.size.height + 20);

    }

    self.previousFrameSize = newFrame.size;
    textView.frame = newFrame;
}

I use previousFrameSizeto keep track of the changing UITextView frame size, and if the frame size ever changes then I increase the size of messageFieldContainer to accommodate the increased text view frame size.

This works perfectly most of the time, except in two situations:

  1. New line, first character

Here is a screen shot of what the text view looks like when a new line has started and you type the line's first character:

enter image description here

  1. New line, second character

Here is a screen shot of what the text view looks like when a new line has started and you type the line's second character:

enter image description here

Here is a screenshot of what the text view looks like once you type the third character of the new line. This is how it should look 100% of the time:

enter image description here

I need to fix this logic so that the text view always looks like the third image, even when you are typing the first or second character of a new line.

3

There are 3 best solutions below

0
On BEST ANSWER

I was able to solve the new line issues by disabling Autolayout in my nib/xib file and setting the UITextView's scrollEnabled property to NO.

Disabling AutoLayout made a minor improvement, but the UITextView would still distort when starting a new line. The only way to solve this was to disable scrolling.

Hopefully someone finds this useful. I wasted hours trying to implement complex AutoLayout solutions before I found a random comment mentioning the above.

0
On

I dealt with this for two days, and turning Autolayout off wasn't an option for me. After searching and trying things I found a solution. Code is in Swift, but it shouldn't be too hard. You basically have to use KVO to monitor your textView content size.

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
    println("Observed")

    //I have to format the textView twice, not sure why, but it is not a mistake.
    // Dont like having to do this, but this has been the only way to make the textview scroll properly on newline.
    let textView:UITextView = object as UITextView
    formatTextViewHeight(textView)
    var topOffset = (textView.bounds.size.height - textView.contentSize.height - textView.contentInset.top * textView.zoomScale) / 2.0
    textView.contentOffset = CGPoint(x: 0, y: -topOffset)
    formatTextViewHeight(textView)

}

My format textview method has to be called twice in the KVO

func formatTextViewHeight(textView: UITextView) {

    let stryBrdPad:CGFloat = 4.0
    self.tableView.beginUpdates()
    self.replyView.frame.size.height = textView.contentSize.height + stryBrdPad
    textView.frame.size.height = textView.contentSize.height
    self.tableView.endUpdates()

}

I am new to the Text APIs so I may be missing something, but I have noticed some popular apps have this problem too. When I tried formatting in textviewDidChange, I noticed in my logs that contentSize did change, but if I set the textView frame to the contentSize and increased my container frame, nothing would happen... even with using layoutIfNeeded, updateConstrainst, setNeedsDisplay, I tried them all..

0
On

I've seen several people around the web who have this issue. If you have a UITextView whose scrollEnabled property is false, it will automatically expand its height after a newline only after another character is typed.

To remedy this, use UITextViewDelegate's textViewDidChange method to listen for changes the text view's text, and call sizeToFit() and layoutIfNeeded().

Example

func textViewDidChange(textView: UITextView) {

    textView.sizeToFit()
    textView.layoutIfNeeded()

}