15

I am using an UITextView that will be expandable by taping a "more" button. The problem is the following:

On iOS6 I use this,

self.DescriptionTextView.text =  @"loong string";

if(self.DescriptionTextView.contentSize.height>self.DescriptionTextView.frame.size.height) { 
    //set up the more button
}

The problem is that on iOS7 the contentSize.height returns a different value (far smaller) than the value it returns on iOS6. Why is this? How to fix it?

iPatel
  • 46,010
  • 16
  • 115
  • 137
user1028028
  • 6,323
  • 9
  • 34
  • 59

4 Answers4

59

The content size property no longer works as it did on iOS 6. Using sizeToFit as others suggest may or may not work depending on a number of factors.

It didn't work for me, so I use this instead:

- (CGFloat)measureHeightOfUITextView:(UITextView *)textView
{
    if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1)
    {
        // This is the code for iOS 7. contentSize no longer returns the correct value, so
        // we have to calculate it.
        //
        // This is partly borrowed from HPGrowingTextView, but I've replaced the
        // magic fudge factors with the calculated values (having worked out where
        // they came from)

        CGRect frame = textView.bounds;

        // Take account of the padding added around the text.

        UIEdgeInsets textContainerInsets = textView.textContainerInset;
        UIEdgeInsets contentInsets = textView.contentInset;

        CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + textView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right;
        CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom;

        frame.size.width -= leftRightPadding;
        frame.size.height -= topBottomPadding;

        NSString *textToMeasure = textView.text;
        if ([textToMeasure hasSuffix:@"\n"])
        {
            textToMeasure = [NSString stringWithFormat:@"%@-", textView.text];
        }

        // NSString class method: boundingRectWithSize:options:attributes:context is
        // available only on ios7.0 sdk.

        NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
        [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping];

        NSDictionary *attributes = @{ NSFontAttributeName: textView.font, NSParagraphStyleAttributeName : paragraphStyle };

        CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
                                                  options:NSStringDrawingUsesLineFragmentOrigin
                                               attributes:attributes
                                                  context:nil];

        CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding);
        return measuredHeight;
    }
    else
    {
        return textView.contentSize.height;
    }
}
tarmes
  • 15,366
  • 10
  • 53
  • 87
  • Thanks, this seems to wok great. can you help on another similar question? http://stackoverflow.com/questions/19029018/dynamically-resize-label-in-ios7 – user1028028 Sep 27 '13 at 11:18
  • It's easy to use next check for iOS version: if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) – JastinBall Oct 08 '13 at 03:15
  • 2
    Best fix I've seen so far to deal with the contentSize.height issue that iOS 7 causes. Only thing I would like to mention is that is would be best to check for system version just in case snapshotViewAfterScreenUpdates does ever change. – VGruenhagen Jan 02 '14 at 23:58
  • 3
    I've updated the code to check for iOS 7 against the system version. – tarmes Jan 06 '14 at 14:28
  • OK so here are my to cents: Fixed in iOS 7.1 (good news!). For iOS 7.0.x calculate the contentSize as said here (or for non-attributed strings like this: CGFloat textViewheight = [self.textView sizeThatFits:CGSizeMake(self.textView.frame.size.width, FLT_MAX)].height; and then set the constant of the textview's height constraint to that height. (you most likely shouldn't be fooling around with frames in autolayout scenarios) – Wirsing Apr 17 '14 at 23:05
  • Perfect.. Work's for me :) – Christian Pappenberger Jul 28 '14 at 16:11
  • Worked for me same issue for iOS 8. On iOS9 textView.contentSize.height works perfect. :) – Gaurav Borole Apr 26 '16 at 09:35
10

Try the answer in the following link, layoutIfNeeded should be called before contentSize.

iOS7 UITextView contentsize.height alternative

The answer:

In iOS7, UITextView uses NSLayoutManager to layout text:

// If YES, then the layout manager may perform glyph generation and layout for a given portion of the text, without having glyphs or layout for preceding portions.  The default is NO.  Turning this setting on will significantly alter which portions of the text will have glyph generation or layout performed when a given generation-causing method is invoked.  It also gives significant performance benefits, especially for large documents.
@property(NS_NONATOMIC_IOSONLY) BOOL allowsNonContiguousLayout;

disable allowsNonContiguousLayout to fix contentSize :

textView.layoutManager.allowsNonContiguousLayout = NO;
Community
  • 1
  • 1
nova
  • 781
  • 11
  • 17
  • According to documentation, allowsNonContiguousLayout is set to false by default. Is there some situation when it is set to true and we have to reset it manually? – Lope Mar 14 '14 at 19:18
  • @Lope I think it may be false by default for layout managers that you make yourself, but it's true by default for the one that the textview makes. Setting it back to false sorted out my layout problems. Thanks, @nova! – Simon Aug 10 '15 at 09:44
2

This link seems to have the answer.

You must use sizeToFit before using contentSize.

Puneet Sharma
  • 9,369
  • 1
  • 27
  • 33
  • 1
    The link says that sizeToFit used to work in iOS 6, but now with iOS 7 there were some additional workarounds. – TPoschel Jun 26 '14 at 01:21
0

Try with following code, Its will be work in both iOS6 and 7, please try it.

CGSize myTextViewSize = [self.myTextView sizeThatFits:CGSizeMake(self.myTextView.frame.size.width, FLT_MAX)];
self.myTextView.height = myTextViewSize.height;
NSLog(@"%f", self.myTextView.height);
iPatel
  • 46,010
  • 16
  • 115
  • 137