advantis
6/14/2013 - 9:45 AM

Automatically avoid keyboard overlapping

Automatically avoid keyboard overlapping

//
//  Copyright © 2012 Yuri Kotov
//

#import "ADVKeyboardManager.h"

@interface UIView (ADVFirstResponder)

- (UIView *) firstResponder;

@end

static BOOL ResponderIsValid(id responder)
{
    return [responder isKindOfClass:[UITextField class]] || [responder isKindOfClass:[UITextView class]];
}

@implementation ADVKeyboardManager
{
    UIView *_firstResponder;
    UIScrollView *_scrollView;
}

#pragma mark - ADVKeyboardManager
- (void) keyboardWillShow:(NSNotification *)notification
{
    if (__builtin_expect(!_firstResponder, NO))
    {
        _firstResponder = [[[UIApplication sharedApplication] keyWindow] firstResponder];
    }

    if (!ResponderIsValid(_firstResponder)) return;

    _scrollView = (UIScrollView *)_firstResponder;
    while (_scrollView && ![_scrollView isKindOfClass:[UIScrollView class]])
    {
        _scrollView = (UIScrollView *)_scrollView.superview;
    }

    if (!_scrollView) return;

    CGRect keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    keyboardFrame = [_scrollView.superview convertRect:keyboardFrame fromView:nil];
    CGRect scrollFrame = [_scrollView.superview convertRect:_scrollView.frame toView:nil];
    CGRect intersection = CGRectIntersection(keyboardFrame, scrollFrame);
    if (!CGRectIsNull(intersection))
    {
        _scrollView.contentInset = UIEdgeInsetsMake(0, 0, intersection.size.height, 0);
        CGRect responderFrame = [_firstResponder.superview convertRect:_firstResponder.frame toView:_scrollView];
        [_scrollView scrollRectToVisible:responderFrame animated:YES];
    }
}

- (void) keyboardWillHide:(NSNotification *)notification
{
    if (_scrollView)
    {
        NSDictionary *userInfo = [notification userInfo];
        NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];

        UIViewAnimationCurve curve;
        [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&curve];

        UIViewAnimationOptions options = curve << 16;
        void(^animations)() = ^{
            _scrollView.contentInset = UIEdgeInsetsZero;
        };
        void(^completion)(BOOL) = ^(BOOL finished) {
            _scrollView = nil;
        };

        [UIView animateWithDuration:duration
                              delay:0.0
                            options:options
                         animations:animations
                         completion:completion];
    }
}

- (void) textFieldDidBeginEditing:(NSNotification *)notification
{
    _firstResponder = [notification object];
}

- (void) textFieldDidEndEditing:(NSNotification *)notification
{
    _firstResponder = nil;
}

- (void) textViewDidBeginEditing:(NSNotification *)notification
{
    _firstResponder = [notification object];
}

- (void) textViewDidEndEditing:(NSNotification *)notification
{
    _firstResponder = nil;
}

- (id) init
{
    self = [super init];
    if (self)
    {
        NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
        [notificationCenter addObserver:self
                               selector:@selector(keyboardWillShow:)
                                   name:UIKeyboardWillShowNotification
                                 object:nil];
        [notificationCenter addObserver:self
                               selector:@selector(keyboardWillHide:)
                                   name:UIKeyboardWillHideNotification
                                 object:nil];
        [notificationCenter addObserver:self
                               selector:@selector(textFieldDidBeginEditing:)
                                   name:UITextFieldTextDidBeginEditingNotification
                                 object:nil];
        [notificationCenter addObserver:self
                               selector:@selector(textFieldDidEndEditing:)
                                   name:UITextFieldTextDidEndEditingNotification
                                 object:nil];
        [notificationCenter addObserver:self
                               selector:@selector(textViewDidBeginEditing:)
                                   name:UITextViewTextDidBeginEditingNotification
                                 object:nil];
        [notificationCenter addObserver:self
                               selector:@selector(textViewDidEndEditing:)
                                   name:UITextViewTextDidEndEditingNotification
                                 object:nil];
    }
    return self;
}

- (void) dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end


@implementation UIView (ADVFirstResponder)

- (UIView *) firstResponder
{
    if ([self isFirstResponder]) return self;

    for (UIView *subview in self.subviews)
    {
        UIView *firstResponder = [subview firstResponder];
        if (firstResponder) return firstResponder;
    }

    return nil;
}

@end
//
//  Copyright © 2012 Yuri Kotov
//

#import <Foundation/Foundation.h>

@interface ADVKeyboardManager : NSObject

@end