Last active
August 29, 2015 14:03
-
-
Save brennanMKE/bea871ceaa430e50555c to your computer and use it in GitHub Desktop.
iOS Keyboard Handling with a Base View Controller
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <UIKit/UIKit.h> | |
@interface BaseViewController : UIViewController | |
#pragma mark - Keyboard Methods | |
#pragma mark - | |
- (void)hideKeyboardWithoutAnimation; | |
- (void)keyboardWillShowWithHeight:(CGFloat)height duration:(CGFloat)duration animationOptions:(UIViewAnimationOptions)animationOptions; | |
- (void)keyboardWillHideWithHeight:(CGFloat)height duration:(CGFloat)duration animationOptions:(UIViewAnimationOptions)animationOptions; | |
- (void)keyboardDidShow; | |
- (void)keyboardDidHide; | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "BaseViewController.h" | |
@interface BaseViewController () | |
@end | |
@implementation BaseViewController { | |
BOOL isKeyboardVisible; | |
} | |
#pragma mark - View Lifecycle | |
#pragma mark - | |
- (void)viewWillAppear:(BOOL)animated { | |
[super viewWillAppear:animated]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardWillShowNotification:) | |
name:UIKeyboardWillShowNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardWillHideNotification:) | |
name:UIKeyboardWillHideNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardDidShowNotification:) | |
name:UIKeyboardDidShowNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] addObserver:self | |
selector:@selector(keyboardDidHideNotification:) | |
name:UIKeyboardDidHideNotification | |
object:nil]; | |
self.navigationController.navigationBar.backgroundColor = self.view.backgroundColor; | |
} | |
- (void)viewWillDisappear:(BOOL)animated { | |
[super viewWillDisappear:animated]; | |
[[NSNotificationCenter defaultCenter] removeObserver:self | |
name:UIKeyboardWillShowNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] removeObserver:self | |
name:UIKeyboardWillHideNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] removeObserver:self | |
name:UIKeyboardDidShowNotification | |
object:nil]; | |
[[NSNotificationCenter defaultCenter] removeObserver:self | |
name:UIKeyboardDidHideNotification | |
object:nil]; | |
} | |
#pragma mark - Keyboard Methods | |
#pragma mark - | |
- (void)hideKeyboardWithoutAnimation { | |
[self keyboardWillHideWithHeight:0.0 duration:0.0 animationOptions:kNilOptions]; | |
} | |
- (void)keyboardWillShowWithHeight:(CGFloat)height duration:(CGFloat)duration animationOptions:(UIViewAnimationOptions)animationOptions { | |
// override if necessary | |
DebugLog(@"%@", NSStringFromSelector(_cmd)); | |
UIScrollView *scrollView = [self mainScrollView]; | |
if (scrollView) { | |
CGFloat bottom = self.bottomLayoutGuide.length; | |
UIEdgeInsets contentInset = scrollView.contentInset; | |
contentInset.bottom = bottom + height; | |
UIEdgeInsets scrollIndicatorInsets = scrollView.scrollIndicatorInsets; | |
scrollIndicatorInsets.bottom = contentInset.bottom; | |
[UIView animateWithDuration:duration delay:0.0 options:animationOptions animations:^{ | |
scrollView.contentInset = contentInset; | |
scrollView.scrollIndicatorInsets = scrollIndicatorInsets; | |
} completion:^(BOOL finished) { | |
}]; | |
} | |
} | |
- (void)keyboardWillHideWithHeight:(CGFloat)height duration:(CGFloat)duration animationOptions:(UIViewAnimationOptions)animationOptions { | |
// override if necessary | |
DebugLog(@"%@", NSStringFromSelector(_cmd)); | |
UIScrollView *scrollView = [self mainScrollView]; | |
if (scrollView) { | |
CGFloat bottom = self.bottomLayoutGuide.length; | |
UIEdgeInsets contentInset = scrollView.contentInset; | |
contentInset.bottom = bottom; | |
UIEdgeInsets scrollIndicatorInsets = scrollView.scrollIndicatorInsets; | |
scrollIndicatorInsets.bottom = contentInset.bottom; | |
[UIView animateWithDuration:duration delay:0.0 options:animationOptions animations:^{ | |
scrollView.contentInset = contentInset; | |
scrollView.scrollIndicatorInsets = scrollIndicatorInsets; | |
} completion:^(BOOL finished) { | |
}]; | |
} | |
} | |
- (void)keyboardDidShow { | |
// override if necessary | |
} | |
- (void)keyboardDidHide { | |
// override if necessary | |
} | |
#pragma mark - Notifications | |
#pragma mark - | |
- (void)keyboardWillShowNotification:(NSNotification *)notification { | |
CGFloat height = [self getKeyboardHeight:notification forBeginning:TRUE]; | |
NSTimeInterval duration = [self getDuration:notification]; | |
UIViewAnimationCurve animationCurve = [self getAnimationCurve:notification]; | |
UIViewAnimationOptions animationOptions = [self animationOptionsWithCurve:animationCurve]; | |
[self keyboardWillShowWithHeight:height duration:duration animationOptions:animationOptions]; | |
} | |
- (void)keyboardWillHideNotification:(NSNotification *)notification { | |
CGFloat height = [self getKeyboardHeight:notification forBeginning:FALSE]; | |
NSTimeInterval duration = [self getDuration:notification]; | |
UIViewAnimationCurve animationCurve = [self getAnimationCurve:notification]; | |
UIViewAnimationOptions animationOptions = [self animationOptionsWithCurve:animationCurve]; | |
[self keyboardWillHideWithHeight:height duration:duration animationOptions:animationOptions]; | |
} | |
- (void)keyboardDidShowNotification:(NSNotification *)notification { | |
isKeyboardVisible = TRUE; | |
[self keyboardDidShow]; | |
} | |
- (void)keyboardDidHideNotification:(NSNotification *)notification { | |
isKeyboardVisible = FALSE; | |
[self keyboardDidHide]; | |
} | |
#pragma mark - Private | |
#pragma mark - | |
- (NSTimeInterval)getDuration:(NSNotification *)notification { | |
NSTimeInterval duration; | |
NSValue *durationValue = [notification.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; | |
[durationValue getValue:&duration]; | |
return duration; | |
} | |
- (CGFloat)getKeyboardHeight:(NSNotification *)notification forBeginning:(BOOL)forBeginning { | |
NSDictionary *info = [notification userInfo]; | |
CGFloat keyboardHeight; | |
NSValue *boundsValue = nil; | |
if (forBeginning) { | |
boundsValue = [info valueForKey:UIKeyboardFrameBeginUserInfoKey]; | |
} | |
else { | |
boundsValue = [info valueForKey:UIKeyboardFrameEndUserInfoKey]; | |
} | |
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; | |
if (UIDeviceOrientationIsLandscape(orientation)) { | |
keyboardHeight = [boundsValue CGRectValue].size.width; | |
} | |
else { | |
keyboardHeight = [boundsValue CGRectValue].size.height; | |
} | |
return keyboardHeight; | |
} | |
- (UIViewAnimationCurve)getAnimationCurve:(NSNotification *)notification { | |
UIViewAnimationCurve animationCurve; | |
NSValue *animationCurveValue = [notification.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; | |
[animationCurveValue getValue:&animationCurve]; | |
return animationCurve; | |
} | |
- (UIViewAnimationOptions)animationOptionsWithCurve:(UIViewAnimationCurve)curve { | |
switch (curve) { | |
case UIViewAnimationCurveEaseInOut: | |
return UIViewAnimationOptionCurveEaseInOut; | |
case UIViewAnimationCurveEaseIn: | |
return UIViewAnimationOptionCurveEaseIn; | |
case UIViewAnimationCurveEaseOut: | |
return UIViewAnimationOptionCurveEaseOut; | |
case UIViewAnimationCurveLinear: | |
return UIViewAnimationOptionCurveLinear; | |
default: | |
// return whatever it provided because iOS 7 uses an undocumented animation value of 7 (not cool, Apple) | |
// http://stackoverflow.com/questions/18837166/how-to-mimic-keyboard-animation-on-ios-7-to-add-done-button-to-numeric-keyboar | |
return (UIViewAnimationOptions)UIViewAnimationOptionCurveLinear; | |
} | |
} | |
- (UIScrollView *)mainScrollView { | |
UIScrollView *scrollView = nil; | |
if (self.view.subviews.count && [self.view.subviews[0] isKindOfClass:[UIScrollView class]]) { | |
scrollView = (UIScrollView *)self.view.subviews[0]; | |
} | |
return scrollView; | |
} | |
- (UIView *)mainContentView { | |
UIView *contentView = nil; | |
UIScrollView *scrollView = [self mainScrollView]; | |
if (scrollView && scrollView.subviews.count) { | |
contentView = scrollView.subviews[0]; | |
} | |
return contentView; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment