Skip to content

Instantly share code, notes, and snippets.

@advantis
Created June 14, 2013 09:45
Show Gist options
  • Save advantis/5780702 to your computer and use it in GitHub Desktop.
Save advantis/5780702 to your computer and use it in GitHub Desktop.
Automatically avoid keyboard overlapping
//
// Copyright © 2012 Yuri Kotov
//
#import <Foundation/Foundation.h>
@interface ADVKeyboardManager : NSObject
@end
//
// 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment