memmons
memmons

Reputation: 40502

Using NSLayoutConstraint on UITextView resets contentSize to {0,0}

I have a UITextView on which I am using an NSLayoutConstraint to dodge the keyboard. Here's the constraint:

self.textViewBottomConstraint = [NSLayoutConstraint constraintWithItem:textView
                                                    attribute:NSLayoutAttributeBottom
                                                    relatedBy:NSLayoutRelationEqual
                                                       toItem:self.view
                                                    attribute:NSLayoutAttributeBottom
                                                   multiplier:1.0
                                                     constant:0.0];
[self.view addConstraint:self.textViewBottomConstraint];

When the keyboard shows/hides I animate the constraint by setting the constraint constant to the keyboard height. However, doing so for some reason resets the contentSize to {0,0}, thus breaking scrolling. I've added a hack to handleKeyboardDidHide: to reset the contentSize to what it was before being reset, but this has some ugly side effects such as the scroll position being reset and the view not scrolling to the cursor position until typing starts.

- (void) handleKeyboardDidShow:(NSNotification *)notification
{
     CGFloat height = [KeyboardObserver sharedInstance].keyboardFrame.size.height;
     self.textView.constant = -height;
     [self.view layoutIfNeeded];
}

- (void) handleKeyboardDidHide:(NSNotification *)notification
{
   // for some reason, setting the bottom constraint resets the contentSize to {0,0}...
   // so let's save it before and reset it after.
   // HACK
   CGSize size = self.textView.contentSize;
   self.textView.constant = 0.0;
   [self.view layoutIfNeeded];
   self.textView.contentSize = size;
}

Anyone know how to avoid this issue altogether?

Upvotes: 0

Views: 545

Answers (1)

matt
matt

Reputation: 536047

I don't know what's wrong with your code, and we can deal with that in detail if you want. But as an initial suggestion, if possible, don't resize the UITextView: just change its content and scroll insets, like this:

- (void) keyboardShow: (NSNotification*) n {
    NSDictionary* d = [n userInfo];
    CGRect r = [d[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    self.tv.contentInset = UIEdgeInsetsMake(0,0,r.size.height,0);
    self.tv.scrollIndicatorInsets = UIEdgeInsetsMake(0,0,r.size.height,0);
}

Even so, I find that you have to wait until the keyboard hide animation completes before resetting those values:

- (void) keyboardHide: (NSNotification*) n {
    NSDictionary* d = [n userInfo];
    NSNumber* curve = d[UIKeyboardAnimationCurveUserInfoKey];
    NSNumber* duration = d[UIKeyboardAnimationDurationUserInfoKey];
    [UIView animateWithDuration:duration.floatValue delay:0
                        options:curve.integerValue << 16
                     animations:
     ^{
         [self.tv setContentOffset:CGPointZero];
     } completion:^(BOOL finished) {
         self.tv.contentInset = UIEdgeInsetsZero;
         self.tv.scrollIndicatorInsets = UIEdgeInsetsZero;
     }];
}

(It may be that that trick would help your code somehow as well.)

Upvotes: 1

Related Questions