iMessage Style Receding Keyboard in an iOS App

In iOS 7 there is a keyboardDismissMode property on UIScrollView. So just set it to "UIScrollViewKeyboardDismissModeInteractive" and you'll get this behavior. Works in UIScrollView subclasses such as UITableView.

self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;

Swift 3:

tableView.keyboardDismissMode = .interactive

Or change it in storyboard (if using it) in attributes inspector for your UIScrollView subclass.


This is an incomplete solution, however it should give you a good starting point.

Add the following ivars to your UIViewController:

CGRect        keyboardSuperFrame; // frame of keyboard when initially displayed
UIView      * keyboardSuperView;  // reference to keyboard view

Add an inputAccessoryView to your text controller. I created an small view to insert as the accessoryView:

accView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
accView.backgroundColor = [UIColor clearColor];
textField.inputAccessoryView = accView;

I added the above code to -(void)loadView

Register to receive UIKeyboardDidShowNotification and UIKeyboardDidHideNotification when view is loaded:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(keyboardWillShow:)
        name:UIKeyboardWillShowNotification
        object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self
        selector:@selector(keyboardDidShow:)
        name:UIKeyboardDidShowNotification
        object:nil];
    return;
}

Add methods to specified as the selectors for the notifications:

// method is called whenever the keyboard is about to be displayed
- (void)keyboardWillShow:(NSNotification *)notification
{
    // makes keyboard view visible incase it was hidden
    keyboardSuperView.hidden = NO;
    return;
}
// method is called whenever the keyboard is displayed
- (void) keyboardDidShow:(NSNotification *)note
{
    // save reference to keyboard so we can easily determine
    // if it is currently displayed
    keyboardSuperView  = textField.inputAccessoryView.superview;

    // save current frame of keyboard so we can reference the original position later
    keyboardSuperFrame = textField.inputAccessoryView.superview.frame;
    return;
}

Add methods to track touched and update keyboard view:

// stops tracking touches to divider
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGRect newFrame;
    CGRect bounds = [[UIScreen mainScreen] bounds];

    newFrame = keyboardSuperFrame;
    newFrame.origin.y = bounds.size.height;  

    if ((keyboardSuperView.superview))
        if (keyboardSuperFrame.origin.y != keyboardSuperView.frame.origin.y)
            [UIView animateWithDuration:0.2
                    animations:^{keyboardSuperView.frame = newFrame;}
                    completion:^(BOOL finished){
                                keyboardSuperView.hidden = YES;
                                keyboardSuperView.frame = keyboardSuperFrame;
                                [textField resignFirstResponder]; }];
    return;
}


// updates divider view position based upon movement of touches
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
   UITouch  * touch;
   CGPoint    point;
   CGFloat    updateY;

   if ((touch = [touches anyObject]))
   {
      point   = [touch locationInView:self.view];
      if ((keyboardSuperView.superview))
      {
         updateY = keyboardSuperView.frame.origin.y;
         if (point.y < keyboardSuperFrame.origin.y)
            return;
         if ((point.y > updateY) || (point.y < updateY))
            updateY = point.y;
         if (keyboardSuperView.frame.origin.y != updateY)
            keyboardSuperView.frame = CGRectMake(keyboardSuperFrame.origin.x,
                                                 point.y,
                                                 keyboardSuperFrame.size.width,
                                                 keyboardSuperFrame.size.height);
      };
   };
   return;
}

Disclaimers:

  • When resigning as first responded, the keyboard moves back to its original position before sliding off screen. To make dismissing the keyboard more fluid, you first need to create an animation to move the keyboard off of the screen and then hide the view. I'll leave this part as an exercise to the readers.
  • I've only tested this on the iOS 5 simulator and with an iPhone with iOS 5. I have not tested this with earlier versions of iOS.

The SlidingKeyboard project I created to test this concept is available from GitHub in the examples directory of BindleKit:

https://github.com/bindle/BindleKit

Edit: Updating example to address first disclaimer.


Vladimir's simple solution will hide the keyboard as the user scrolls down. However to finish the question regarding iMessage, in order to keep a TextField always visible and anchored to the top of the keyboard, you need to implement these methods:

- (UIView *) inputAccessoryView {
     // Return your textfield, buttons, etc
}

- (BOOL) canBecomeFirstResponder {
    return YES;
}

Here's a good tutorial breaking it down more