Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resizing UITextView when keyboard appears in iOS7

This question has been asked a couple of times, but I wasn't really able to find an answer...

In iOS6 I used the following to resize an UITextView whenever the keyboard appeared. Under iOS7 behavior is not as it should be (in my case, it seems like nothing is resizing at all). I suspect the cause to be the auto-layout / constraint behavior of iOS7. Any suggestions? ("notePad" is my UITextView)?

- (void)keyboardWasShown:(NSNotification*)aNotification
{
    NSDictionary* info = [aNotification userInfo];
    CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;

    //NSLog(@"KeyboardSize: %f.%f", kbSize.width, kbSize.height);

    UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, (kbSize.width > kbSize.height ? 
    kbSize.height : kbSize.width), 0);
    self.notePad.contentInset = contentInsets;
    self.notePad.scrollIndicatorInsets = contentInsets;
}
like image 766
eEra Avatar asked Oct 07 '13 15:10

eEra


2 Answers

If you're using auto-layout at your views the following method may help you.

First define a IBOutlet for your bottom layout guide constraint and link with storyboard element.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *textViewBottomConst;

Second add observers for keyboard notifications.

- (void)observeKeyboard {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}

Finally the methods that handles keyboard changes.

- (void)keyboardWillShow:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];
    NSValue *kbFrame = [info objectForKey:UIKeyboardFrameEndUserInfoKey];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
    CGRect keyboardFrame = [kbFrame CGRectValue];

    CGRect finalKeyboardFrame = [self.view convertRect:keyboardFrame fromView:self.view.window];

    int kbHeight = finalKeyboardFrame.size.height;

    int height = kbHeight + self.textViewBottomConst.constant;

    self.textViewBottomConst.constant = height;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (void)keyboardWillHide:(NSNotification *)notification {
    NSDictionary *info = [notification userInfo];

    NSTimeInterval animationDuration = [[info objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    self.textViewBottomConst.constant = 10;

    [UIView animateWithDuration:animationDuration animations:^{
        [self.view layoutIfNeeded];
    }];
}

This method supports orientation changes and different keyboard sizes. Hope it helps.

like image 119
Boran Avatar answered Oct 18 '22 10:10

Boran


Your code is logically correct. When keyboard appear you shouldn't almost never change the frame of an object with the scrollview behaviour, but you should only change the insets. The insets should change relative to the current version because iOS7 take care of adjust for navigation bar. If you provide a new insets probably you will broke something in UI. Your code is broken on iOS7 for two main reason:

  1. You must add auto layout constraint to textview container. (Probably your text view is bigger then you expect)
  2. You shouldn't change insets in absolute way.

Here are the steps to properly configure a textview:

  • In xib (or storyboard) add constraint to top, left, right, bottom to the container (in my case {0, 0, 0, 0} as shown below

Autolayout constraint

  • Register for keyboard notifications

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    
  • In keyboardWillShow and keyboardWillHide don't change the frame, but change the insets relatively to the existing one.

    - (void)keyboardWillShow:(NSNotification *)notification
    {
        // Take frame with key: UIKeyboardFrameEndUserInfoKey because we want the final frame not the begin one
        NSValue *keyboardFrameValue = [notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
        CGRect keyboardFrame = [keyboardFrameValue CGRectValue];
    
        UIEdgeInsets contentInsets = self.textView.contentInset;
        contentInsets.bottom = CGRectGetHeight(keyboardFrame);
    
        self.textView.contentInset = contentInsets;
        self.textView.scrollIndicatorInsets = contentInsets;
    }
    
    - (void)keyboardWillHide:(NSNotification *)notification
    {
        UIEdgeInsets contentInsets = self.textView.contentInset;
        contentInsets.bottom = .0;
    
        self.textView.contentInset = contentInsets;
        self.textView.scrollIndicatorInsets = contentInsets;
    }
    
    • Then remember to remove observers
like image 35
Gigisommo Avatar answered Oct 18 '22 10:10

Gigisommo