9

I'm trying to resize a text view according to content & also it's sibling and parent container.

Below code is working fine in iOS 6

   if (/* less than ios 7 */) {
        CGRect frame = _textView.frame;
        CGSize conSize = _textView.contentSize;
        CGFloat difference = conSize.height - frame.size.height;

        frame.size.height += difference;
        _textView.frame = frame;

        UIScrollView *parentView = (UIScrollView *)_textView.superview;
        // adjust views residing below this text view.

        // sibling view
        UIView *belowView = // access it somehow
        CGRect frame1 = belowView.frame;

        frame1.origin.y += difference;
        belowView.frame = frame1;
        // adjust parent scroll view, increase height.
        CGSize frame3 = parentView.contentSize;

        frame3.height += difference;
        parentView.contentSize = frame3;
    } else {
       // tried
       [_textView sizeToFit]; 
       [_textView layoutIfNeeded];
       [parentView sizeToFit]; 
       [parentView layoutIfNeeded];
    }

Tried to follow iOS 7 solution from: How do I size a UITextView to its content on iOS 7?

but not working.

Any pointers?

Working code solution from @NSBouzouki

if (/* ios 7 */) {
             [_textView.layoutManager ensureLayoutForTextContainer:_textView.textContainer];
            [_textView layoutIfNeeded];
}
            CGRect frame = _textView.frame;
            CGSize conSize = _textView.contentSize;
            CGFloat difference = conSize.height - frame.size.height;

            frame.size.height += difference;
            _textView.frame = frame;

            UIScrollView *parentView = (UIScrollView *)_textView.superview;
            // adjust views residing below this text view.

            // sibling view
            UIView *belowView = // access it somehow
            CGRect frame1 = belowView.frame;

            frame1.origin.y += difference;
            belowView.frame = frame1;
            // adjust parent scroll view, increase height.
            CGSize frame3 = parentView.contentSize;

            frame3.height += difference;
            parentView.contentSize = frame3;
Community
  • 1
  • 1
Piyuesh
  • 1,006
  • 1
  • 9
  • 18

2 Answers2

26

It seems UITextView's contentSize property is not correctly set in iOS 7 till viewDidAppear:. This is probably because NSLayoutManager lays out the text lazily and the entire text must be laid out for contentSize to be correct. The ensureLayoutForTextContainer: method forces layout of the provided text container after which usedRectForTextContainer: can be used for getting the bounds. In order to get total width and height correctly, textContainerInset property must be taken into account. The following method worked for me.

 - (CGRect)contentSizeRectForTextView:(UITextView *)textView
    {
        [textView.layoutManager ensureLayoutForTextContainer:textView.textContainer];
        CGRect textBounds = [textView.layoutManager usedRectForTextContainer:textView.textContainer];
        CGFloat width =  (CGFloat)ceil(textBounds.size.width + textView.textContainerInset.left + textView.textContainerInset.right);
        CGFloat height = (CGFloat)ceil(textBounds.size.height + textView.textContainerInset.top + textView.textContainerInset.bottom);
        return CGRectMake(0, 0, width, height);
    }

Additionally, it seems UITextView's setContentSize: method is called from layoutSubviews. So, calling layoutIfNeeded on a textView (which itself calls layoutSubviews) after calling ensureLayoutForTextContainer: on its layoutManager, should make the textView's contentSize correct.

[someTextView.layoutManager ensureLayoutForTextContainer:someTextView.textContainer];
[someTextView layoutIfNeeded]; 
// someTextView.contentSize should now have correct value
James Nelson
  • 1,551
  • 1
  • 17
  • 23
Ivica M.
  • 4,467
  • 1
  • 20
  • 16
  • Follow below link for the accurate answer: http://trio-hasim.blogspot.in/2014/01/get-uitextview-content-size-in-ios7.html – Suraj Mirajkar Apr 09 '14 at 07:08
  • Please also note that the resize should be done at minimum after layout is calculated in viewDidLayoutSubview to ensure that some math on the layoutContainer have been executed. If you update content from internet, use layoutIfNeeded which will trigger the layout and then update the size in the viewDidLayoutSubview. – Hugues BR Jul 29 '15 at 20:15
1

GrowingTextViewHandler is an NSObject subclass which resizes text view as user types text. Here is how you can use it.

 @interface ViewController ()<UITextViewDelegate>

 @property (weak, nonatomic) IBOutlet UITextView *textView;
 @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint;
 @property (strong, nonatomic) GrowingTextViewHandler *handler;

 @end

 @implementation ViewController

 - (void)viewDidLoad {
   [super viewDidLoad];
   self.handler = [[GrowingTextViewHandler alloc]initWithTextView:self.textView withHeightConstraint:self.heightConstraint];
   [self.handler updateMinimumNumberOfLines:3 andMaximumNumberOfLine:8];
}

 - (void)textViewDidChange:(UITextView *)textView {
   [self.handler resizeTextViewWithAnimation:YES];
}
@end
hsusmita
  • 282
  • 3
  • 16