6

I have a requirement to add chat functionality into an upcoming project.

In the meantime I have been trying to implement what I expected to be the simple matter of having a UIView at the bottom of the screen which has a UITextView inside, which will animate up with the keyboard when the user taps on the UITextView.

I have it working, however unfortunately the animation for the keyboard is slightly behind that of the view above it. Here is my implementation so far:

Register the keyboard notifications:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

Keyboard notification method:

- (void)keyboardWillShow:(NSNotification*)notification
{
    CGFloat duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
    NSInteger curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];

    [UIView animateWithDuration:duration delay:0 options:curve animations:^{

        CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
        _chatViewBottomConstraint.constant = keyboardFrame.size.height;
        [self.view layoutIfNeeded];

    } completion:nil];
}

Has anyone else done similar, and are able to provide a better solution for me?

Nick
  • 939
  • 1
  • 12
  • 19

2 Answers2

9

This is working for me:

- (void)keyboardWillShow:(id)keyboardDidShow
{
    [UIView beginAnimations:nil context:NULL];

    NSDictionary *userInfo = [keyboardDidShow userInfo];
    [UIView setAnimationDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
    [self.view layoutIfNeeded];

    [UIView commitAnimations];
}

- (void)keyboardWillHide:(id)keyboardDidHide
{
    [UIView beginAnimations:nil context:NULL];

    NSDictionary *userInfo = [keyboardDidHide userInfo];
    [UIView setAnimationDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
    [UIView setAnimationCurve:[userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];            
    [self.view layoutIfNeeded];

    [UIView commitAnimations];
}

UPDATE: Or you can do the same with blocks:

- (void)keyboardWillShow:(id)keyboardDidShow
{
    NSDictionary *userInfo = [keyboardDidShow userInfo];
    [UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]
                          delay:0.f
                        options:[[keyboardDidShow userInfo][UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
                     animations:^{
        ...
    } completion:^(BOOL finished) {
        ...
    }];
}

- (void)keyboardWillHide:(id)keyboardDidHide
{
    NSDictionary *userInfo = [keyboardDidHide userInfo];
    [UIView animateWithDuration:[userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]
                          delay:0.f
                        options:[[keyboardDidHide userInfo][UIKeyboardAnimationCurveUserInfoKey] intValue] << 16
                     animations:^{
        ...
    } completion:^(BOOL finished) {
        ...
    }];
}
electronix384128
  • 6,625
  • 11
  • 45
  • 67
  • Why are you using the deprecated animation methods instead of the block-based syntax? – Jesse Rusak Jun 07 '14 at 18:43
  • Well, I am still using Xcode5. Since I am still developing for iOS7 at the moment. It does not show the code as deprecated. But I have updated my answer with blocks, I guess that is what you mean ;) – electronix384128 Jun 07 '14 at 19:00
  • Sorry, I guess they're not deprecated, but they've been "discouraged" (according to the docs) since iOS 4. – Jesse Rusak Jun 08 '14 at 00:41
  • ok sure.. I can see why... having it in a block is less error prone ;) – electronix384128 Jun 08 '14 at 11:52
  • 1
    Using the blocks method is what appears to be causing me the problem of the delay between keyboard and the view reaching their destination. If I use the animation methods it works fine. Any ideas? Inside the animation block I have: _chatViewBottomConstraint.constant = keyboardFrame.size.height; [self.view layoutIfNeeded]; – Nick Jun 08 '14 at 13:18
  • 1
    There's a bug in Ben's code; the curve can't be passed directly to options. See: http://stackoverflow.com/questions/7327249/ios-how-to-convert-uiviewanimationcurve-to-uiviewanimationoptions – Jesse Rusak Jun 08 '14 at 14:10
  • That's true! I'm glad you mentioned that, had that also in my code, since i switched to the block style! I've updated my answer! (" << 16") This works for me :) – electronix384128 Jun 08 '14 at 23:05
5

The notification userInfo dictionaries have both animation duration (UIKeyboardAnimationDurationUserInfoKey) and curve (UIKeyboardAnimationCurveUserInfoKey) information; if you use both of them, your animation should match the keyboard animation timing.

Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102