HanXu
HanXu

Reputation: 5597

Trouble when trying to change UITextView height dynamically

I'm using iOS7.

I want to change the height of my UITextView dynamically according to the content height. However, I find in iOS7, the contentSize is a mess. For example, when I delete a line, the contentSize will not change, but I expect its height to decrease.

So I write the following

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    //  increase a line
    if ([text isEqualToString:@"\n"]) {
        _FRAME_SET_H(textView, textView.contentSize.height + 24.0f);

    //  decrease a line
    } else if (range.length == 1 && [textView.text hasSuffix:@"\n"]) {
        _FRAME_SET_H(textView, textView.contentSize.height - 24.0f);

    } else {
        _FRAME_SET_H(textView, textView.contentSize.height);
    }

    return YES;
}

Everything works fine, until I input a very long text:

enter image description here

The contentSize will not change when the text is long enough to cause a automatically line change!

Could anyone help me?

What I want is simple: change the height of the UITextView according to its content. However, I have spent more than two days on it, but still not solved.

The UITextView in iOS7 is so bug.


I tried to follow Uptown Apps's solution. Following is my new code (changed a bit to fit in my other project):

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView {
    CGRect rect = [textView.text
                   boundingRectWithSize:CGSizeMake(300, CGFLOAT_MAX)
                   options:NSStringDrawingUsesLineFragmentOrigin
                   attributes:@{NSFontAttributeName: textView.font}
                   context:nil];
    _FRAME_SET_H(textView, rect.size.height);

    _FRAME_SET_H(self, _FRAME_H(textView) + _BLOCK_PADDING * 2);
}

However, trouble remains. In the following image, the white rect is the UITextView, and the black background is its superview.

When I start the app, the UITextView's height is 0, and the screen looks like: enter image description here

Then I type 'A', the screen turns into: enter image description here

You see there is two problems: 1) the height is not enough. 2) the caret is strange!

Then I type some more 'a', the screen turns into: enter image description here

Then I type a 'return' to change a line, the screen turns into: enter image description here

Yes, it does not change! But I expect it to increase its height to include the new blank line.

Then I type a 'A', the screen turns into: enter image description here

The height is increased, but the new text is not showing, neither is the caret. I guess it is also due to that the height is not enough.

Then I type another 'a', the screen turns into: enter image description here

Letters appear, but only a half...

By the way, when I use UILabel, I can get the correct text height using this method!!!! (i.e. calling boundingRectWithSize:)

Upvotes: 2

Views: 7847

Answers (3)

Vivek Deore
Vivek Deore

Reputation: 71

You can change the height of the text view dynamically, using:

[textView sizeToFit];

But the problem is that, if the content inside the text view is too little, it will resize to smaller than the original size. Here is the best solution for this:

- (void)textViewDidChange:(UITextView *)textView{
    CGRect frameForTextView=textView.frame;
    [textView sizeToFit];
    if (textView.frame.size.height < frameForTextView.size.height) {
        textView.frame=frameForComments;
    }
    else
    {
        //Do other UI adjustment here when height of textView increased than default size      
    }
}

Upvotes: 0

Uptown Apps
Uptown Apps

Reputation: 707

--Edit--

See How do I size a UITextView to its content?

Once the text has changed, you can go back to your original solution of using the contentSize. I adjusted this code to use a maxHeight

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    return YES;
}

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

--Original Answer--

Have you tried waiting until the text has changed and then use the NSString methods to get the size? I haven't tested this but it should get you started in the right direction.

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    return YES;
}

- (void)textViewDidChange:(UITextView *)textView{

    CGFloat myMaxSize = 568.0f; // Set to max height you would ever want your textView to expand to

    CGRect frameRect = textView.frame;
    CGRect rect = [textView.text 
boundingRectWithSize:CGSizeMake(frameRect.size.width, CGFLOAT_MAX)
             options:NSStringDrawingUsesLineFragmentOrigin 
          attributes:@{NSFontAttributeName: textView.font} 
             context:nil];

    CGSize size = rect.size;
    if (size.height > myMaxSize) {
        size.height = myMaxSize;
    }

    frameRect.size = size;
    [textView setFrame:frameRect];

}

Upvotes: 5

Matteo Gobbi
Matteo Gobbi

Reputation: 17707

You can get the correct height of the text by this function:

CGSize textSize = [text sizeWithFont:[UIFont systemFontOfSize:13.0f] constrainedToSize:CGSizeMake(textView.width, 20000) lineBreakMode: NSLineBreakByWordWrapping];

float text_height = textSize.height;

This function constrain the text in the width of your textView. So in according of the width, it return the height of the text in that space.

Let me know!

Upvotes: 0

Related Questions