diff --git a/.gitignore b/.gitignore
index bb1e388..b1ab962 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ user.*.espressostorage
Sparkle/*.app
*.zip
PXListView
+*.xccheckout
diff --git a/ExampleApp/KGAppDelegate.m b/ExampleApp/KGAppDelegate.m
index ed96142..7e60b75 100644
--- a/ExampleApp/KGAppDelegate.m
+++ b/ExampleApp/KGAppDelegate.m
@@ -28,6 +28,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
[showButton addTarget:self action:@selector(showAction:) forControlEvents:UIControlEventTouchUpInside];
[self.window.rootViewController.view addSubview:showButton];
+ [KGModal sharedInstance].responsiveToKeyboard = YES;
[KGModal sharedInstance].closeButtonType = KGModalCloseButtonTypeRight;
[self.window makeKeyAndVisible];
@@ -57,30 +58,27 @@ - (void)showAction:(id)sender{
welcomeLabel.shadowOffset = CGSizeMake(0, 1);
[contentView addSubview:welcomeLabel];
- CGRect infoLabelRect = CGRectInset(contentView.bounds, 5, 5);
- infoLabelRect.origin.y = CGRectGetMaxY(welcomeLabelRect)+5;
- infoLabelRect.size.height -= CGRectGetMinY(infoLabelRect) + 50;
- UILabel *infoLabel = [[UILabel alloc] initWithFrame:infoLabelRect];
- infoLabel.text = @"KGModal is an easy drop in control that allows you to display any view "
+ CGRect infoTextRect = CGRectInset(contentView.bounds, 5, 5);
+ infoTextRect.origin.y = CGRectGetMaxY(welcomeLabelRect)+5;
+ infoTextRect.size.height -= CGRectGetMinY(infoTextRect) + 50;
+ UITextView *infoText = [[UITextView alloc] initWithFrame:infoTextRect];
+ infoText.text = @"KGModal is an easy drop in control that allows you to display any view "
"in a modal popup. The modal will automatically scale to fit the content view "
- "and center it on screen with nice animations!";
- infoLabel.numberOfLines = 6;
- infoLabel.textColor = [UIColor whiteColor];
- infoLabel.textAlignment = NSTextAlignmentCenter;
- infoLabel.backgroundColor = [UIColor clearColor];
- infoLabel.shadowColor = [UIColor blackColor];
- infoLabel.shadowOffset = CGSizeMake(0, 1);
- [contentView addSubview:infoLabel];
+ "and center it on screen with nice animations!\n"
+ "(Tap here and then tap button below)";
+ infoText.textColor = [UIColor blackColor];
+ infoText.textAlignment = NSTextAlignmentCenter;
+ infoText.backgroundColor = [UIColor whiteColor];
+ [contentView addSubview:infoText];
- CGFloat btnY = CGRectGetMaxY(infoLabelRect)+5;
+ CGFloat btnY = CGRectGetMaxY(infoTextRect)+5;
CGFloat btnH = CGRectGetMaxY(contentView.frame)-5 - btnY;
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- btn.frame = CGRectMake(infoLabelRect.origin.x, btnY, infoLabelRect.size.width, btnH);
+ btn.frame = CGRectMake(infoTextRect.origin.x, btnY, infoTextRect.size.width, btnH);
[btn setTitle:@"Close Button Right" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(changeCloseButtonType:) forControlEvents:UIControlEventTouchUpInside];
[contentView addSubview:btn];
-// [[KGModal sharedInstance] setCloseButtonLocation:KGModalCloseButtonLocationRight];
[[KGModal sharedInstance] showWithContentView:contentView andAnimated:YES];
}
@@ -105,7 +103,9 @@ - (void)changeCloseButtonType:(id)sender{
KGModal *modal = [KGModal sharedInstance];
KGModalCloseButtonType type = modal.closeButtonType;
- if(type == KGModalCloseButtonTypeLeft){
+ [modal endEditing:NO];
+
+ if (type == KGModalCloseButtonTypeLeft) {
modal.closeButtonType = KGModalCloseButtonTypeRight;
[button setTitle:@"Close Button Right" forState:UIControlStateNormal];
}else if(type == KGModalCloseButtonTypeRight){
diff --git a/ExampleApp/KGModalExample.xcodeproj/project.xcworkspace/xcshareddata/KGModalExample.xccheckout b/ExampleApp/KGModalExample.xcodeproj/project.xcworkspace/xcshareddata/KGModalExample.xccheckout
deleted file mode 100644
index b2f46a1..0000000
--- a/ExampleApp/KGModalExample.xcodeproj/project.xcworkspace/xcshareddata/KGModalExample.xccheckout
+++ /dev/null
@@ -1,41 +0,0 @@
-
-
-
-
- IDESourceControlProjectFavoriteDictionaryKey
-
- IDESourceControlProjectIdentifier
- 5C978CE1-221A-4169-AF81-B64C6BBF112C
- IDESourceControlProjectName
- KGModalExample
- IDESourceControlProjectOriginsDictionary
-
- FB6C026C-C1C4-455C-BA11-CFF8C0912A70
- https://github.com/kgn/KGModal.git
-
- IDESourceControlProjectPath
- ExampleApp/KGModalExample.xcodeproj/project.xcworkspace
- IDESourceControlProjectRelativeInstallPathDictionary
-
- FB6C026C-C1C4-455C-BA11-CFF8C0912A70
- ../../..
-
- IDESourceControlProjectURL
- https://github.com/kgn/KGModal.git
- IDESourceControlProjectVersion
- 110
- IDESourceControlProjectWCCIdentifier
- FB6C026C-C1C4-455C-BA11-CFF8C0912A70
- IDESourceControlProjectWCConfigurations
-
-
- IDESourceControlRepositoryExtensionIdentifierKey
- public.vcs.git
- IDESourceControlWCCIdentifierKey
- FB6C026C-C1C4-455C-BA11-CFF8C0912A70
- IDESourceControlWCCName
- KGModal
-
-
-
-
diff --git a/KGModal.h b/KGModal.h
index 10ce934..b47b9c9 100644
--- a/KGModal.h
+++ b/KGModal.h
@@ -26,6 +26,8 @@ typedef NS_ENUM(NSUInteger, KGModalCloseButtonType){
@interface KGModal : NSObject
+@property (nonatomic) BOOL responsiveToKeyboard;
+
// Determines if the modal should dismiss if the user taps outside of the modal view
// Defaults to YES
@property (nonatomic) BOOL tapOutsideToDismiss;
@@ -79,4 +81,7 @@ typedef NS_ENUM(NSUInteger, KGModalCloseButtonType){
// run the completion after the modal is hidden
- (void)hideAnimated:(BOOL)animated withCompletionBlock:(void(^)())completion;
+// Send endEditing message to containing view
+-(void) endEditing:(BOOL) force;
+
@end
diff --git a/KGModal.m b/KGModal.m
index 1ac5a57..4633ddd 100644
--- a/KGModal.m
+++ b/KGModal.m
@@ -9,10 +9,20 @@
#import "KGModal.h"
#import
+#pragma mark - Utils for Keyboard response
+
+#define swap(a, b) do{typeof(a) odd13var=a; a=b; b=odd13var;}while(0)
+
+@interface UIView (KGFirstResponder)
+- (UIView *)kgFindFirstResponder;
+@end
+
+#pragma mark -
+
CGFloat const kFadeInAnimationDuration = 0.3;
CGFloat const kTransformPart1AnimationDuration = 0.2;
CGFloat const kTransformPart2AnimationDuration = 0.1;
-CGFloat const kDefaultCloseButtonPadding = 17.0;
+CGFloat const kDefaultPadding = 17.0;
NSString *const KGModalGradientViewTapped = @"KGModalGradientViewTapped";
@@ -80,7 +90,7 @@ -(void)setCloseButtonType:(KGModalCloseButtonType)closeButtonType {
CGRect closeFrame = self.closeButton.frame;
if(closeButtonType == KGModalCloseButtonTypeRight){
- closeFrame.origin.x = round(CGRectGetWidth(self.containerView.frame)-kDefaultCloseButtonPadding-CGRectGetWidth(closeFrame)/2);
+ closeFrame.origin.x = round(CGRectGetWidth(self.containerView.frame)-kDefaultPadding-CGRectGetWidth(closeFrame)/2);
}else{
closeFrame.origin.x = 0;
}
@@ -88,6 +98,85 @@ -(void)setCloseButtonType:(KGModalCloseButtonType)closeButtonType {
}
}
+#pragma mark - Methods for Keyboard response
+
+-(void)setResponsiveToKeyboard:(BOOL)responsiveToKeyboard {
+ _responsiveToKeyboard = responsiveToKeyboard;
+
+ // Clear anything before
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
+
+ // Add if needed
+ if(responsiveToKeyboard){
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(keyboardWasShown:)
+ name:UIKeyboardDidShowNotification
+ object:nil];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(keyboardWillBeHidden:)
+ name:UIKeyboardWillHideNotification
+ object:nil];
+ }
+}
+
+-(void) _adjustPositionForKeyboard:(CGSize) keyboardSize inTime:(double) duration {
+ CGRect containerViewRect = self.containerView.frame;
+ CGRect freeScreen = self.window.bounds;
+
+ if (UIDeviceOrientationIsLandscape(self.window.rootViewController.interfaceOrientation)) {
+ swap(freeScreen.size.width, freeScreen.size.height);
+ }
+
+ // TODO: could be more accurate
+ // Simple go through. Should work on 99% cases, but may have exceptions anyways.
+ freeScreen.size.height -= keyboardSize.height;
+ CGFloat newY = (freeScreen.size.height - containerViewRect.size.height)/2 + freeScreen.origin.y;
+
+ // A threshhold to check if animation really needed
+ if (ABS(newY - containerViewRect.origin.y) < 2) {
+ containerViewRect.origin.y = newY;
+ self.containerView.frame = containerViewRect;
+ } else {
+ containerViewRect.origin.y = newY;
+ UIView *container = self.containerView;
+ [UIView animateWithDuration:duration
+ animations:^{
+ container.frame = containerViewRect;
+ }];
+ }
+}
+
+-(void) keyboardWasShown:(NSNotification *) aNotification {
+ UIView *selectedView = [self.containerView kgFindFirstResponder];
+ // Do only this modal contains the firstResponder
+ if (selectedView) {
+ CGSize keyboardSize = [[[aNotification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
+ if (UIDeviceOrientationIsLandscape(self.window.rootViewController.interfaceOrientation))
+ swap(keyboardSize.width, keyboardSize.height);
+
+ if ([selectedView respondsToSelector:@selector(inputAccessoryView)]) {
+ UIView *accessoryView = [selectedView inputAccessoryView];
+ if (accessoryView) {
+ keyboardSize = CGSizeMake(keyboardSize.width,
+ keyboardSize.height + accessoryView.frame.size.height);
+ }
+ }
+
+ double animDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+
+ [self _adjustPositionForKeyboard:keyboardSize inTime:animDuration];
+ }
+}
+
+-(void) keyboardWillBeHidden:(NSNotification *) aNotification {
+ double animDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
+
+ [self _adjustPositionForKeyboard:CGSizeZero inTime:animDuration];
+}
+
+#pragma mark -
+
- (void)showWithContentView:(UIView *)contentView{
[self showWithContentView:contentView andAnimated:YES];
}
@@ -110,8 +199,7 @@ - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated {
self.window.rootViewController = viewController;
self.viewController = viewController;
- CGFloat padding = 17;
- CGRect containerViewRect = CGRectInset(contentView.bounds, -padding, -padding);
+ CGRect containerViewRect = CGRectInset(contentView.bounds, -kDefaultPadding, -kDefaultPadding);
containerViewRect.origin.x = containerViewRect.origin.y = 0;
containerViewRect.origin.x = round(CGRectGetMidX(self.window.bounds)-CGRectGetMidX(containerViewRect));
containerViewRect.origin.y = round(CGRectGetMidY(self.window.bounds)-CGRectGetMidY(containerViewRect));
@@ -120,19 +208,12 @@ - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated {
containerView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|
UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
containerView.layer.rasterizationScale = [[UIScreen mainScreen] scale];
- contentView.frame = (CGRect){padding, padding, contentView.bounds.size};
+ contentView.frame = (CGRect){kDefaultPadding, kDefaultPadding, contentView.bounds.size};
[containerView addSubview:contentView];
[viewController.view addSubview:containerView];
self.containerView = containerView;
KGModalCloseButton *closeButton = [[KGModalCloseButton alloc] init];
-
- if(self.closeButtonType == KGModalCloseButtonTypeRight){
- CGRect closeFrame = closeButton.frame;
- closeFrame.origin.x = CGRectGetWidth(containerView.bounds)-CGRectGetWidth(closeFrame);
- closeButton.frame = closeFrame;
- }
-
[closeButton addTarget:self action:@selector(closeAction:) forControlEvents:UIControlEventTouchUpInside];
[containerView addSubview:closeButton];
self.closeButton = closeButton;
@@ -143,6 +224,9 @@ - (void)showWithContentView:(UIView *)contentView andAnimated:(BOOL)animated {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(tapCloseAction:)
name:KGModalGradientViewTapped object:nil];
+ // Force adding keyboard observers if needed
+ [self setResponsiveToKeyboard:self.responsiveToKeyboard];
+
// The window has to be un-hidden on the main thread
// This will cause the window to display
dispatch_async(dispatch_get_main_queue(), ^{
@@ -243,6 +327,10 @@ - (void)setModalBackgroundColor:(UIColor *)modalBackgroundColor{
}
}
+-(void)endEditing:(BOOL)force {
+ [self.containerView endEditing:force];
+}
+
- (void)dealloc{
[self cleanup];
}
@@ -427,3 +515,24 @@ - (UIImage *)closeButtonImage{
}
@end
+
+#pragma mark -
+
+@implementation UIView (KGFirstResponder)
+
+- (UIView *)kgFindFirstResponder
+{
+ if (self.isFirstResponder)
+ return self;
+
+ for (UIView *subView in self.subviews) {
+ UIView *firstResponder = [subView kgFindFirstResponder];
+
+ if (firstResponder != nil) {
+ return firstResponder;
+ }
+ }
+ return nil;
+}
+@end
+