Tuesday, June 5, 2012

How do I size a UITextView to its content?


Is there a good way to adjust the size of a UITextView to conform to its content? Say for instance I have a UITextView that contains one line of text:



"Hello world"



I then add another line of text:



"Goodbye world"



Is there a good way in Cocoa Touch to get the rect that will hold all of the lines in the text view so that I can adjust the parent view accordingly?



As another example, look at the Notes field for events in the Calendar application--note how the cell (and the UITextView it contains) expands to hold all lines of text in the notes string.


Source: Tips4all

7 comments:

  1. There is actually a very easy way to do resizing of the UITextView to its correct height of the content. It can be done using the UITextView contentSize.

    CGRect frame = _textView.frame;
    frame.size.height = _textView.contentSize.height;
    _textView.frame = frame;


    One thing to note is that the correct contentSize is only available after the UITextView has been added to the view with addSubview. Prior to that it is equal to frame.size

    ReplyDelete
  2. In my (limited) experience,

    - (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode


    does not respect newline characters, so you can end up with a lot shorter CGSize than is actually required.

    - (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size


    does seem to respect the newlines.

    Also, the text isn't actually rendered at the top of the UITextView. In my code, I set the new height of the UITextView to be 24 pixels larger than the height returned by the sizeOfFont methods.

    ReplyDelete
  3. Did you try [textView sizeThatFits:textView.bounds] ?

    Edit: sizeThatFits returns the size but does not actually resize the component. I'm not sure if that's what you want, or if [textView sizeToFit] is more what you were looking for. In either case, I do not know if it will perfectly fit the content like you want, but it's the first thing to try.

    ReplyDelete
  4. Another method is the find the size a particular string will take up using the NSString method:

    -(CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size

    This returns the size of the rectangle that fits the given string with the given font. Pass in a size with the desired width and a maximum height, and then you can look at the height returned to fit the text. There is a version that lets you specify line break mode also.

    You can then use the returned size to change the size of your view to fit.

    ReplyDelete
  5. Combined with Mike McMaster's answer, you might want to do something like:

    [myTextView setDelegate: self];

    ...

    - (void)textViewDidChange:(UITextView *)textView {
    if (myTextView == textView) {
    // it changed. Do resizing here.
    }
    }

    ReplyDelete
  6. Hope this helps:

    - (void)textViewDidChange:(UITextView *)textView {
    CGSize textSize = textview.contentSize;
    if (textSize != textView.frame.size)
    textView.frame.size = textSize;
    }

    ReplyDelete
  7. I found out a way to resize the height of a text field according to the text inside it and also arrange a label below it based on the height of the text field! Here is the code.

    UITextView *_textView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 300, 10)];
    NSString *str = @"This is a test text view to check the auto increment of height of a text view. This is only a test. The real data is something different.";
    _textView.text = str;

    [self.view addSubview:_textView];
    CGRect frame = _textView.frame;
    frame.size.height = _textView.contentSize.height;
    _textView.frame = frame;

    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 5 + frame.origin.y + frame.size.height, 300, 20)];
    lbl.text = @"Hello!";
    [self.view addSubview:lbl];

    ReplyDelete