1

I'm trying to create a UITextView where the height increase dynamically. There is a UIView to group this UITextView with a UIButton.

I've added a observer to the NSnotificationCenter for the UITextViewTextDidChangeNotification notification.

According to the height of the current tapping text , I create a new CGRect:

CGRect newRect = [contentTextView.text boundingRectWithSize:CGSizeMake(222, CGFLOAT_MAX)
                                                         options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) attributes:@{NSFontAttributeName:font} context:nil];

Then, I change the size of the current UIView:

CGRect tmp = commentView.frame;
CGRect fitRectForView = CGRectMake(tmp.origin.x, tmp.origin.y - abs(newRectH - commentView.frame.size.height), tmp.size.width, newRect.size.height);
            commentView.frame = fitRectForView; 

Finally, I change the height of my UITextView:

CGRect fitRectForTextView = CGRectMake(contentTextView.frame.origin.x, contentTextView.frame.origin.y, contentTextView.frame.size.width,newRectH);
            contentTextView.frame = fitRectForTextView;

Here is the log of the origin and the size of my contentTextView variable before and after the fitting:

//Before
contentTextView origin : 0.000000 ; 0.000000
contentTextView size : 33.000000 ; 251.000000
//After
contentTextView origin : 0.000000 ; 0.000000
contentTextView size : 84.000000 ; 251.000000

Screenshot of the result

With this screenshot, you can see that only my commentView's height is changing. I put a constraint on the send button to keep it on the bottom of the UIView (commentView) but it's not effective.

I can't find my mistake.

Here is my first source: create-a-multi-line-uitextfield

Community
  • 1
  • 1
brcebn
  • 1,571
  • 1
  • 23
  • 46

1 Answers1

0

If your UITextView is on your View Controller's view and not inside a Keyboard input accessory view, then this is how I usually do it with constraints:

-(void)viewDidLoad
{
    ...

    myTextView = [[UITextView alloc] init];
    myTextView.scrollEnabled = NO;

    myTextView.translateAutoresizingMaskIntoConstraints = NO;

    // -----------------------------------------------
    // set textview delegate for delegate method
    // -----------------------------------------------
    myTextView.delegate = self;

    // -----------------------------------------------
    // put your code to setup all the constraint 
    // for your textView here
    //
    // Note: alternatively, you can set your constraints
    // using Interface Builder.
    // -----------------------------------------------


}

// -----------------------------------------------
// This is the UITextView delegate method so make
// sure your .h file has conformed to 
// UITextViewDelegate method
// -----------------------------------------------
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
    ...

    // let autolayout know the textView needs to relayout
    [textView invalidateIntrinsicContentSize];

    return YES;
}

Additional info

If you want the button to appear the bottom of your view, then you need to set the button to pin to the bottom of your UIView container.

With constraints in code, this is how it's done:

id views = @{"containerView": self.containerView, @"contentTextView": self. contentTextView, @"myButton": self.myButton};

// make your container view expand to fill up your root view
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[containerView]|" options:0 metrics:nil views:views]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[containerView]|" options:0 metrics:nil views:views]];

// text view constraints
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[contentTextView]-10-[myButton]-10-|" options:0 metrics:nil views:views]];
[self.containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[contentTextView]-10-|" options:0 metrics:nil views:views]];

// button constraints

// note here, we make the button bottom edge always same as text view's bottom edge.

[self.containerView addConstraint:[NSLayoutConstraint constraintWithItem:self.myButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.contentTextView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
Zhang
  • 11,549
  • 7
  • 57
  • 87
  • I would rather add constraints from Interface Builder. Like that I can have an idea of what I'm doing. By the way. I don't understand why the button is not on the bottom while the height of the commentView is growing. Do you have an idea ? I think the solution could come from this point. – brcebn May 20 '14 at 08:00
  • You can add your constraints anywhere you like, the important part is the invalidateIntrinsicContentSize line and the way you init your UITextView. As for the button not appearing at the bottom, make sure you set a constraint where the button's bottom is always at bottom of the UIView (see updated answer). – Zhang May 20 '14 at 08:27
  • I have noticed that the height of my `contentTextView` is never update (according to the logs). How is it possible ? – brcebn May 20 '14 at 08:31
  • UITextView needs to have the scrollEnabled property set to NO if you're using constraints I believe. – Zhang May 20 '14 at 08:39
  • I tried but it's not working either. I've found inspiration form this issue [create-a-multi-line-uitextfield](http://stackoverflow.com/questions/6398519/objective-c-how-to-create-a-multi-line-uitextfield) – brcebn May 20 '14 at 08:47
  • It seems like you want to put a text view inside a keyboard input accessory view which doesn't work well with Autolayout. You'll need to look for another answer. – Zhang May 20 '14 at 08:52
  • Basically, the text view is not inside a keyboard input accessory but I didn't know that was existing. I'll take a look to that. Thank you. – brcebn May 20 '14 at 09:09
  • I finally found the problem of the height of my `contentTextField`. The text was never updated because of the `contentTextView = [[UITextView alloc] init];`. There was a conflit somewhere. Without that, and with the code you gave me it's working. Thank you ! – brcebn May 20 '14 at 09:47