From 16925fe96b2efa1780c7fa378df95c621c110239 Mon Sep 17 00:00:00 2001 From: rotunda Date: Wed, 26 Jun 2013 16:41:57 +0200 Subject: [PATCH 1/6] add support for text input --- SIAlertView/SIAlertView.h | 7 +++ SIAlertView/SIAlertView.m | 49 +++++++++++++++++++ .../SIAlertViewExample/ViewController.m | 2 + 3 files changed, 58 insertions(+) diff --git a/SIAlertView/SIAlertView.h b/SIAlertView/SIAlertView.h index 1062f68..c5d1718 100644 --- a/SIAlertView/SIAlertView.h +++ b/SIAlertView/SIAlertView.h @@ -32,6 +32,11 @@ typedef NS_ENUM(NSInteger, SIAlertViewTransitionStyle) { SIAlertViewTransitionStyleDropDown }; +typedef NS_ENUM(NSInteger, SIAlertViewStyle) { + SIAlertViewStyleDefault = 0, + SIAlertViewStyleTextInput +}; + @class SIAlertView; typedef void(^SIAlertViewHandler)(SIAlertView *alertView); @@ -39,7 +44,9 @@ typedef void(^SIAlertViewHandler)(SIAlertView *alertView); @property (nonatomic, copy) NSString *title; @property (nonatomic, copy) NSString *message; +@property (nonatomic, copy, readonly) NSString *inputText; +@property (nonatomic, assign) SIAlertViewStyle alertViewStyle; // default is SIAlertViewStyleDefault @property (nonatomic, assign) SIAlertViewTransitionStyle transitionStyle; // default is SIAlertViewTransitionStyleSlideFromBottom @property (nonatomic, assign) SIAlertViewBackgroundStyle backgroundStyle; // default is SIAlertViewButtonTypeGradient diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index e9237e3..f604dd5 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -24,6 +24,7 @@ #define CONTENT_PADDING_TOP 12 #define CONTENT_PADDING_BOTTOM 10 #define BUTTON_HEIGHT 44 +#define TEXTFIELD_HEIGHT 28 #define CONTAINER_WIDTH 300 const UIWindowLevel UIWindowLevelSIAlert = 1999.0; // don't overlap system's alert @@ -44,6 +45,7 @@ @interface SIAlertView () @property (nonatomic, strong) UILabel *titleLabel; @property (nonatomic, strong) UILabel *messageLabel; +@property (nonatomic, strong) UITextField *textField; @property (nonatomic, strong) UIView *containerView; @property (nonatomic, strong) NSMutableArray *buttons; @@ -167,6 +169,9 @@ - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrie #pragma mark - SIAlert +@interface SIAlertView() +@end + @implementation SIAlertView + (void)initialize @@ -262,6 +267,12 @@ + (void)hideBackgroundAnimated:(BOOL)animated }]; } +#pragma mark - Getters + +- (NSString *)inputText { + return self.textField ? self.textField.text : @""; +} + #pragma mark - Setters - (void)setTitle:(NSString *)title @@ -648,6 +659,14 @@ - (void)validateLayout self.messageLabel.frame = CGRectMake(CONTENT_PADDING_LEFT, y, self.containerView.bounds.size.width - CONTENT_PADDING_LEFT * 2, height); y += height; } + if(self.textField) { + if (y > CONTENT_PADDING_TOP) { + y += GAP; + } + CGFloat height = TEXTFIELD_HEIGHT; + self.textField.frame = CGRectMake(CONTENT_PADDING_LEFT, y, self.containerView.bounds.size.width - CONTENT_PADDING_LEFT * 2, height); + y += height; + } if (self.items.count > 0) { if (y > CONTENT_PADDING_TOP) { y += GAP; @@ -687,6 +706,12 @@ - (CGFloat)preferredHeight } height += [self heightForMessageLabel]; } + if (self.textField) { + if (height > CONTENT_PADDING_TOP) { + height += GAP; + } + height += TEXTFIELD_HEIGHT; + } if (self.items.count > 0) { if (height > CONTENT_PADDING_TOP) { height += GAP; @@ -742,6 +767,9 @@ - (void)setup [self setupContainerView]; [self updateTitleLabel]; [self updateMessageLabel]; + if(self.alertViewStyle == SIAlertViewStyleTextInput) { + [self setupTextField]; + } [self setupButtons]; [self invaliadateLayout]; } @@ -819,6 +847,20 @@ - (void)updateMessageLabel [self invaliadateLayout]; } +- (void)setupTextField +{ + if(!self.textField) { + self.textField = [[UITextField alloc] initWithFrame:self.bounds]; + self.textField.delegate = self; + self.textField.borderStyle = UITextBorderStyleBezel; + [self.containerView addSubview:self.textField]; +#if DEBUG_LAYOUT + self.textField.backgroundColor = [UIColor redColor]; +#endif + } + [self invaliadateLayout]; +} + - (void)setupButtons { self.buttons = [[NSMutableArray alloc] initWithCapacity:self.items.count]; @@ -894,6 +936,13 @@ - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag } } +#pragma mark - UITextField delegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + [textField resignFirstResponder]; + return YES; +} + #pragma mark - UIAppearance setters - (void)setViewBackgroundColor:(UIColor *)viewBackgroundColor diff --git a/SIAlertViewExample/SIAlertViewExample/ViewController.m b/SIAlertViewExample/SIAlertViewExample/ViewController.m index 449d258..69edc42 100644 --- a/SIAlertViewExample/SIAlertViewExample/ViewController.m +++ b/SIAlertViewExample/SIAlertViewExample/ViewController.m @@ -135,6 +135,7 @@ - (IBAction)alert2:(id)sender - (IBAction)alert3:(id)sender { SIAlertView *alertView = [[SIAlertView alloc] initWithTitle:nil andMessage:@"Message3"]; + alertView.alertViewStyle = SIAlertViewStyleTextInput; [alertView addButtonWithTitle:@"Cancel" type:SIAlertViewButtonTypeCancel handler:^(SIAlertView *alertView) { @@ -144,6 +145,7 @@ - (IBAction)alert3:(id)sender type:SIAlertViewButtonTypeDefault handler:^(SIAlertView *alertView) { NSLog(@"OK Clicked"); + NSLog(@"Textinput: %@", alertView.inputText); }]; alertView.transitionStyle = SIAlertViewTransitionStyleDropDown; alertView.backgroundStyle = SIAlertViewBackgroundStyleSolid; From 3d1d3f4b7b4331ab8136f66a62d5d18f81582e95 Mon Sep 17 00:00:00 2001 From: rotunda Date: Thu, 27 Jun 2013 09:54:53 +0200 Subject: [PATCH 2/6] Fixed nil value when when textfield is empty --- SIAlertView/SIAlertView.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index f604dd5..4308102 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -852,6 +852,7 @@ - (void)setupTextField if(!self.textField) { self.textField = [[UITextField alloc] initWithFrame:self.bounds]; self.textField.delegate = self; + self.textField.text = @""; self.textField.borderStyle = UITextBorderStyleBezel; [self.containerView addSubview:self.textField]; #if DEBUG_LAYOUT From 80bf8dcf00cc3196710e0eeb0631867ae2b9037e Mon Sep 17 00:00:00 2001 From: rotunda Date: Thu, 27 Jun 2013 12:15:17 +0200 Subject: [PATCH 3/6] Fixed repositioning alert when keyboard is present --- SIAlertView/SIAlertView.m | 54 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index 4308102..4e73c89 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -49,6 +49,8 @@ @interface SIAlertView () @property (nonatomic, strong) UIView *containerView; @property (nonatomic, strong) NSMutableArray *buttons; +@property (nonatomic, assign) CGFloat keyboardOffset; + @property (nonatomic, assign, getter = isLayoutDirty) BOOL layoutDirty; + (NSMutableArray *)sharedQueue; @@ -374,6 +376,13 @@ - (void)dismissAnimated:(BOOL)animated cleanup:(BOOL)cleanup if (self.willDismissHandler) { self.willDismissHandler(self); } + + if(self.textField) { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; + [self.textField resignFirstResponder]; + } + [[NSNotificationCenter defaultCenter] postNotificationName:SIAlertViewWillDismissNotification object:self userInfo:nil]; } @@ -636,9 +645,10 @@ - (void)validateLayout NSLog(@"%@, %@", self, NSStringFromSelector(_cmd)); #endif + CGFloat availableHeight = self.bounds.size.height - self.keyboardOffset; CGFloat height = [self preferredHeight]; CGFloat left = (self.bounds.size.width - CONTAINER_WIDTH) * 0.5; - CGFloat top = (self.bounds.size.height - height) * 0.5; + CGFloat top = (availableHeight - height) * 0.5; self.containerView.transform = CGAffineTransformIdentity; self.containerView.frame = CGRectMake(left, top, CONTAINER_WIDTH, height); self.containerView.layer.shadowPath = [UIBezierPath bezierPathWithRoundedRect:self.containerView.bounds cornerRadius:self.containerView.layer.cornerRadius].CGPath; @@ -666,6 +676,7 @@ - (void)validateLayout CGFloat height = TEXTFIELD_HEIGHT; self.textField.frame = CGRectMake(CONTENT_PADDING_LEFT, y, self.containerView.bounds.size.width - CONTENT_PADDING_LEFT * 2, height); y += height; + } if (self.items.count > 0) { if (y > CONTENT_PADDING_TOP) { @@ -858,6 +869,8 @@ - (void)setupTextField #if DEBUG_LAYOUT self.textField.backgroundColor = [UIColor redColor]; #endif + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil]; } [self invaliadateLayout]; } @@ -944,6 +957,45 @@ - (BOOL)textFieldShouldReturn:(UITextField *)textField { return YES; } +#pragma mark - Keyboard notification handlers + +-(void)keyboardWillShowNotification:(NSNotification *)notification { + [self moveAlertForKeyboard:notification up:YES]; +} +-(void)keyboardWillHideNotification:(NSNotification *)notification { + [self moveAlertForKeyboard:notification up:NO]; +} + +- (void)moveAlertForKeyboard:(NSNotification*)notification up:(BOOL)up { + NSDictionary* userInfo = [notification userInfo]; + NSTimeInterval animationDuration; + UIViewAnimationCurve animationCurve; + CGRect keyboardEndFrame; + + [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; + [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; + [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame]; + + //calculate new position + CGRect containerFrame = self.containerView.frame; + CGRect keyboardFrame = [self.containerView convertRect:keyboardEndFrame toView:nil]; + CGFloat adjustedHeight = self.bounds.size.height; + if(up) { + adjustedHeight -= keyboardFrame.size.height; + } + containerFrame.origin.y = (adjustedHeight - containerFrame.size.height) / 2; + + [UIView beginAnimations:nil context:nil]; + [UIView setAnimationDuration:animationDuration]; + [UIView setAnimationCurve:animationCurve]; + self.containerView.frame = containerFrame; + [UIView commitAnimations]; + + // Set keyboardOffset to the width of the keyboard. + // This property is used to adjust the alertView y position on willRotate, i.e. before the rotation occurs. Therefore the width is used instead of height. + self.keyboardOffset = up ? keyboardFrame.size.width : 0; +} + #pragma mark - UIAppearance setters - (void)setViewBackgroundColor:(UIColor *)viewBackgroundColor From 744d018b0128b315059ef5ebcac94d4a85e5673d Mon Sep 17 00:00:00 2001 From: rotunda Date: Thu, 27 Jun 2013 13:19:44 +0200 Subject: [PATCH 4/6] textfield now becomes firstResponder when alert is presented --- SIAlertView/SIAlertView.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index 4e73c89..a5f5e61 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -359,6 +359,8 @@ - (void)show NSInteger index = [[SIAlertView sharedQueue] indexOfObject:self]; if (index < [SIAlertView sharedQueue].count - 1) { [self dismissAnimated:YES cleanup:NO]; // dismiss to show next alert view + } else if(self.textField) { + [self.textField becomeFirstResponder]; } }]; } From 2609046ced1b827cae4f0624113aa4a2bd233579 Mon Sep 17 00:00:00 2001 From: rotunda Date: Fri, 5 Jul 2013 11:05:41 +0200 Subject: [PATCH 5/6] Fixed textfield orientation support --- SIAlertView/SIAlertView.h | 2 +- SIAlertView/SIAlertView.m | 20 +++++++++++++------ .../SIAlertViewExample/ViewController.m | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/SIAlertView/SIAlertView.h b/SIAlertView/SIAlertView.h index c5d1718..d0a93bb 100644 --- a/SIAlertView/SIAlertView.h +++ b/SIAlertView/SIAlertView.h @@ -34,7 +34,7 @@ typedef NS_ENUM(NSInteger, SIAlertViewTransitionStyle) { typedef NS_ENUM(NSInteger, SIAlertViewStyle) { SIAlertViewStyleDefault = 0, - SIAlertViewStyleTextInput + SIAlertViewStylePlainTextInput }; @class SIAlertView; diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index a5f5e61..a08c4c1 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -780,7 +780,7 @@ - (void)setup [self setupContainerView]; [self updateTitleLabel]; [self updateMessageLabel]; - if(self.alertViewStyle == SIAlertViewStyleTextInput) { + if(self.alertViewStyle == SIAlertViewStylePlainTextInput) { [self setupTextField]; } [self setupButtons]; @@ -980,10 +980,10 @@ - (void)moveAlertForKeyboard:(NSNotification*)notification up:(BOOL)up { //calculate new position CGRect containerFrame = self.containerView.frame; - CGRect keyboardFrame = [self.containerView convertRect:keyboardEndFrame toView:nil]; + CGRect convertedKeyboardFrame = [self convertRect:keyboardEndFrame fromView:self.window]; CGFloat adjustedHeight = self.bounds.size.height; if(up) { - adjustedHeight -= keyboardFrame.size.height; + adjustedHeight -= convertedKeyboardFrame.size.height; } containerFrame.origin.y = (adjustedHeight - containerFrame.size.height) / 2; @@ -993,9 +993,17 @@ - (void)moveAlertForKeyboard:(NSNotification*)notification up:(BOOL)up { self.containerView.frame = containerFrame; [UIView commitAnimations]; - // Set keyboardOffset to the width of the keyboard. - // This property is used to adjust the alertView y position on willRotate, i.e. before the rotation occurs. Therefore the width is used instead of height. - self.keyboardOffset = up ? keyboardFrame.size.width : 0; + //keyboardOffset is used to adjust the alertView y position on willRotate, i.e. before the rotation occurs. Therefore the height is set dependent of the current orientation + if(up) { + self.keyboardOffset = UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation]) ? keyboardEndFrame.size.height : keyboardEndFrame.size.width; + } else { + self.keyboardOffset = 0; + } +} + ++ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view { + UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window]; + return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil]; } #pragma mark - UIAppearance setters diff --git a/SIAlertViewExample/SIAlertViewExample/ViewController.m b/SIAlertViewExample/SIAlertViewExample/ViewController.m index 69edc42..c238b5c 100644 --- a/SIAlertViewExample/SIAlertViewExample/ViewController.m +++ b/SIAlertViewExample/SIAlertViewExample/ViewController.m @@ -135,7 +135,7 @@ - (IBAction)alert2:(id)sender - (IBAction)alert3:(id)sender { SIAlertView *alertView = [[SIAlertView alloc] initWithTitle:nil andMessage:@"Message3"]; - alertView.alertViewStyle = SIAlertViewStyleTextInput; + alertView.alertViewStyle = SIAlertViewStylePlainTextInput; [alertView addButtonWithTitle:@"Cancel" type:SIAlertViewButtonTypeCancel handler:^(SIAlertView *alertView) { From 0087b3b82033ad3d13f60964fd1a01e2928888cc Mon Sep 17 00:00:00 2001 From: rotunda Date: Wed, 10 Jul 2013 08:29:53 +0200 Subject: [PATCH 6/6] clean up --- SIAlertView/SIAlertView.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/SIAlertView/SIAlertView.m b/SIAlertView/SIAlertView.m index a08c4c1..97a19e4 100644 --- a/SIAlertView/SIAlertView.m +++ b/SIAlertView/SIAlertView.m @@ -1001,11 +1001,6 @@ - (void)moveAlertForKeyboard:(NSNotification*)notification up:(BOOL)up { } } -+ (CGRect) convertRect:(CGRect)rect toView:(UIView *)view { - UIWindow *window = [view isKindOfClass:[UIWindow class]] ? (UIWindow *) view : [view window]; - return [view convertRect:[window convertRect:rect fromWindow:nil] fromView:nil]; -} - #pragma mark - UIAppearance setters - (void)setViewBackgroundColor:(UIColor *)viewBackgroundColor