[Quicktips] iOS - Follow Keyboard Animation Behaviour
Autor: vitor navarro | Publicado: 2014-08-02T20:45:00-03:00

On getting back to iOS programming I restarted to check into interesting subjects, like the right way of creating view controllers, behaviours and more.

One thing I had to create these last days was some code for a text field to follow the keyboard open/close animation. Then it come to me that we were going to use that behaviour was needed in more places and that it didn't belong to the view controller neither to the view using it.

So in order to achieve that I decided to create a behaviour class which features are:
To receive a target view
Register under keyboard events
Animate the target view to follow the keyboard open/close animation
Keep target view before (on top) of keyboard, meaning that target will be hidden when keyboard is closed
This set of features don't break the single responsibility principle since it is responsible only for controlling the animation behaviour of a view following the iOS keyboard.

To achieve our desire the class must subscribe to keyboard notifications and follow keyboard info dictionary in order to animate the same way the keyboard does.


<![CDATA[
//Subscribing to Keyboard will show and will hide notifications 
-(void)subscribeToKeyboardEvents{
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillShow:) 
                                                 name:UIKeyboardWillShowNotification 
                                               object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(keyboardWillHide:) 
                                                 name:UIKeyboardWillHideNotification 
                                               object:nil];
}
- (void)animateWithKeyboardInfo:(NSDictionary *)keyboardInfo
{
//1.
    NSInteger animationCurve = [keyboardInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
    CGFloat duration = [keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
    CGRect keyboardEndFrame = [keyboardInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
    
//2.
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:duration];
    [UIView setAnimationCurve:animationCurve];
    [UIView setAnimationBeginsFromCurrentState:YES];
//3.
    CGRect frame = self.targetView.frame;
    if(keyboardEndFrame.origin.y >= [UIScreen mainScreen].bounds.size.height){
        frame.origin.y = keyboardEndFrame.origin.y + frame.size.height;
    }
    else{
        frame.origin.y = keyboardEndFrame.origin.y - frame.size.height;
    }
    [self.targetView setFrame:frame];
    [UIView commitAnimations];
}
]]>


In 1. we retrieve the type of animation, the duration and the final position of the keyboard. The problem with the animation type is that Apple uses a internal value which only works directly with the old animation style.
To use it with animationWithDuration methods we would have to shift the value, this isn't easy to understand and read later so is preferable to keep the old style in this case.

In 2. we use the animation calls on UIView to prepare animation with keyboard info.

In 3. we animate using the keyboard final position, in my case I'm positioning the view right above keyboard, and when dismissed the view will be hidden outside of the screen in the bottom. Also we have to commitAnimations so evertyhing will work properly.

That is all we need to create a behaviour that works with any view.

The class and the demo are available on github.