Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed a couple of bugs: #18

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 92 additions & 39 deletions KeyboardTextFieldDemo/IQKeyBoardManager/IQKeyboardManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ - (void)keyboardWillShow:(NSNotification*)aNotification;
- (void)keyboardWillHide:(NSNotification*)aNotification;
- (void)textFieldViewDidBeginEditing:(NSNotification*)notification;
- (void)textFieldViewDidEndEditing:(NSNotification*)notification;
- (void)textFieldViewDidChange:(NSNotification*)notification;

- (void)tapRecognized:(UITapGestureRecognizer*)gesture;

Expand Down Expand Up @@ -187,10 +188,11 @@ -(id)initUniqueInstance
// Registering for textView notification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldViewDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldViewDidEndEditing:) name:UITextViewTextDidEndEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textFieldViewDidChange:) name:UITextViewTextDidChangeNotification object:nil];

tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapRecognized:)];
[tapGesture setDelegate:self];

// Default settings
[self setKeyboardDistanceFromTextField:10.0];
animationDuration = 0.25;
Expand Down Expand Up @@ -256,6 +258,8 @@ -(void)setEnable:(BOOL)enable
//Sending a fake notification for keyboardWillHide to retain view's original frame.
[self keyboardWillHide:nil];

[self removeToolbarIfRequired];

//Setting NO to _enable.
_enable = enable;

Expand Down Expand Up @@ -313,8 +317,8 @@ +(UIScrollView*)superScrollView:(UIView*)view

while (superview)
{
if ([superview isKindOfClass:[UIScrollView class]])
{
if ([superview isKindOfClass:[UIScrollView class]])
{
return (UIScrollView*)superview;
}
else superview = superview.superview;
Expand All @@ -327,7 +331,7 @@ +(UIScrollView*)superScrollView:(UIView*)view
+ (UIViewController*) topMostController
{
UIViewController *topController = [[IQKeyboardManager sharedManager] rootViewController];

// Getting topMost ViewController
while ([topController presentedViewController]) topController = [topController presentedViewController];

Expand All @@ -340,7 +344,7 @@ +(UIViewController*)currentViewController;
UIViewController *currentViewController = [IQKeyboardManager topMostController];

while ([currentViewController isKindOfClass:[UINavigationController class]] && [(UINavigationController*)currentViewController topViewController])
currentViewController = [(UINavigationController*)currentViewController topViewController];
currentViewController = [(UINavigationController*)currentViewController topViewController];

return currentViewController;
}
Expand Down Expand Up @@ -368,9 +372,6 @@ -(void)adjustFrame
// We are unable to get textField object while keyboard showing on UIWebView's textField.
if (textFieldView == nil) return;

// Boolean to know keyboard is showing/hiding
isKeyboardShowing = YES;

// Getting KeyWindow object.
UIWindow *window = [self keyWindow];
// Getting RootViewController.
Expand All @@ -380,7 +381,7 @@ -(void)adjustFrame
CGRect textFieldViewRect = [[textFieldView superview] convertRect:textFieldView.frame toView:window];
// Getting RootViewRect.
CGRect rootViewRect = [[rootController view] frame];

CGFloat move = 0;
// Move positive = textField is hidden.
// Move negative = textField is showing.
Expand All @@ -406,9 +407,9 @@ -(void)adjustFrame

// Getting it's superScrollView.
UIScrollView *superScrollView = [IQKeyboardManager superScrollView:textFieldView];

//If there was a lastScrollView.
if (lastScrollView)
if (lastScrollView)
{
//If we can't find current superScrollView, then setting lastScrollView to it's original form.
if (superScrollView == nil)
Expand All @@ -431,14 +432,14 @@ -(void)adjustFrame
lastScrollView = superScrollView;
startingContentOffset = superScrollView.contentOffset;
}

// Special case for ScrollView.
// If we found lastScrollView then setting it's contentOffset to show textField.
if (lastScrollView)
{
UIView *lastView = textFieldView;
UIScrollView *superScrollView = lastScrollView;

while (superScrollView)
{
CGRect lastViewRect = [[lastView superview] convertRect:lastView.frame toView:superScrollView];
Expand All @@ -454,9 +455,10 @@ -(void)adjustFrame
superScrollView = [IQKeyboardManager superScrollView:lastView];
}
}

//Going ahead. No else if.


//Special case for UITextView(When it's hight is too big to fit on screen.
{
CGFloat initialMove = move;
Expand Down Expand Up @@ -492,8 +494,8 @@ -(void)adjustFrame
}];
}
}


// Special case for iPad modalPresentationStyle.
if ([[IQKeyboardManager topMostController] modalPresentationStyle] == UIModalPresentationFormSheet ||
[[IQKeyboardManager topMostController] modalPresentationStyle] == UIModalPresentationPageSheet)
Expand Down Expand Up @@ -588,14 +590,15 @@ -(void)adjustFrame
// Keyboard Will hide. So setting rootViewController to it's default frame.
- (void)keyboardWillHide:(NSNotification*)aNotification
{
//If it's not a fake notification generated by [self setEnable:NO].
//If it's not a fake notification generated by [self setEnable:NO].
if (aNotification != nil) kbShowNotification = nil;

if (_enable == NO) return;

// We are unable to get textField object while keyboard showing on UIWebView's textField.
if (textFieldView == nil) return;


//Due to orientation callback we need to set it's original position.
[UIView animateWithDuration:animationDuration animations:^{
textFieldView.frame = textFieldViewIntialFrame;
Expand All @@ -604,6 +607,7 @@ - (void)keyboardWillHide:(NSNotification*)aNotification
// Boolean to know keyboard is showing/hiding
isKeyboardShowing = NO;


// Getting keyboard animation duration
CGFloat aDuration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
if (aDuration!= 0.0f)
Expand All @@ -616,19 +620,28 @@ - (void)keyboardWillHide:(NSNotification*)aNotification
lastScrollView = nil;
startingContentOffset = CGPointZero;
// Setting rootViewController frame to it's original position.
[self setRootViewFrame:topViewBeginRect];
if (!CGRectIsEmpty(topViewBeginRect))
{
[self setRootViewFrame:topViewBeginRect];

topViewBeginRect = CGRectNull;
}
}

// UIKeyboard Will show
-(void)keyboardWillShow:(NSNotification*)aNotification
{
kbShowNotification = aNotification;
// Boolean to know keyboard is showing/hiding
isKeyboardShowing = YES;

// Store for reference
kbShowNotification = aNotification;

if (_enable == NO) return;

//Due to orientation callback we need to resave it's original frame.
textFieldViewIntialFrame = textFieldView.frame;

// Getting keyboard animation duration
CGFloat duration = [[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];

Expand Down Expand Up @@ -657,10 +670,31 @@ -(void)keyboardWillShow:(NSNotification*)aNotification
break;
}

[self adjustFrame];
}

#pragma mark - UITextFieldView Delegate methods
// Bug fix for iOS 7.0.x - http://stackoverflow.com/questions/18966675/uitextview-in-ios7-clips-the-last-line-of-text-string
-(void)textFieldViewDidChange:(NSNotification*)notification
{
UITextView *textView = (UITextView *)notification.object;

CGRect line = [textView caretRectForPosition:
textView.selectedTextRange.start];
CGFloat overflow = line.origin.y + line.size.height
- ( textView.contentOffset.y + textView.bounds.size.height
- textView.contentInset.bottom - textView.contentInset.top );
if ( overflow > 0 ) {
// We are at the bottom of the visible text and introduced a line feed, scroll down (iOS 7 does not do it)
// Scroll caret to visible area
CGPoint offset = textView.contentOffset;
offset.y += overflow + 7; // leave 7 pixels margin
// Cannot animate with setContentOffset:animated: or caret will not appear
[UIView animateWithDuration:.2 animations:^{
[textView setContentOffset:offset];
}];
}
}

// Removing fetched object.
-(void)textFieldViewDidEndEditing:(NSNotification*)notification
{
Expand All @@ -679,20 +713,22 @@ -(void)textFieldViewDidBeginEditing:(NSNotification*)notification
{
// Getting object
textFieldView = notification.object;

textFieldViewIntialFrame = textFieldView.frame;

//If autoToolbar enable, then add toolbar on all the UITextField/UITextView's if required.
if (_enableAutoToolbar)
{
//UITextView special case. Keyboard Notification is firing before textView notification so we need to resign it first and then again set it as first responder to add toolbar on it.
if ([textFieldView isKindOfClass:[UITextView class]] && textFieldView.inputAccessoryView == nil)
// in iOS 7+ Keyboard Notification sometimes fires before textView notification so we need to resign it first and then again set it as first responder to add toolbar on it.
// By victor - this happens on both UITextField and UITextView
if (textFieldView.inputAccessoryView == nil)
{
UIView *view = textFieldView;

//Resigning becoming first responder with some delay.
[UIView animateWithDuration:0.00001 animations:^{
[self addToolbarIfRequired];

}completion:^(BOOL finished) {
[view resignFirstResponder];
[view becomeFirstResponder];
Expand All @@ -703,19 +739,18 @@ -(void)textFieldViewDidBeginEditing:(NSNotification*)notification
[self addToolbarIfRequired];
}
}

if (_enable == NO) return;
if (_enable == NO) return;

[textFieldView.window addGestureRecognizer:tapGesture];

if (isKeyboardShowing == NO)

// We should save rootViewRect initially no matter keyboard is showing or not, as of iOS 7 keyboard could show early or later
if (CGRectIsEmpty(topViewBeginRect))
{
// keyboard is not showing(At the beginning only). We should save rootViewRect.
UIViewController *rootController = [IQKeyboardManager topMostController];
topViewBeginRect = rootController.view.frame;
}

// keyboard is already showing. adjust frame.
[self adjustFrame];
}

Expand Down Expand Up @@ -760,7 +795,7 @@ -(NSArray*)responderViews
{
// Getting all siblings
NSArray *siblings = textFieldView.superview.subviews;

//Array of (UITextField/UITextView's).
NSMutableArray *textFields = [[NSMutableArray alloc] init];

Expand All @@ -777,7 +812,7 @@ -(NSArray*)responderViews
else if (_toolbarManageBehaviour == IQAutoToolbarByTag)
{
return [textFields sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

if ([(UIView*)obj1 tag] < [(UIView*)obj2 tag]) return NSOrderedAscending;

else if ([(UIView*)obj1 tag] > [(UIView*)obj2 tag]) return NSOrderedDescending;
Expand Down Expand Up @@ -810,7 +845,7 @@ -(void)addToolbarIfRequired
if (![textField inputAccessoryView])
{
[textField addPreviousNextDoneOnKeyboardWithTarget:self previousAction:@selector(previousAction:) nextAction:@selector(nextAction:) doneAction:@selector(doneAction:)];

// If firstTextField, then previous should not be enabled.
if ([siblings objectAtIndex:0] == textField)
{
Expand All @@ -826,6 +861,21 @@ -(void)addToolbarIfRequired
}
}

-(void)removeToolbarIfRequired
{
// Getting all the sibling textFields.
NSArray *siblings = [self responderViews];

for (UITextField *textField in siblings)
{
if ([textField inputAccessoryView].tag == NSIntegerMin)
{
[textField.inputAccessoryView removeFromSuperview];
[textField setInputAccessoryView:nil];
}
}
}

// Previous button action.
-(void)previousAction:(UISegmentedControl*)segmentedControl
{
Expand Down Expand Up @@ -874,6 +924,7 @@ -(void)addDoneOnKeyboardWithTarget:(id)target action:(SEL)action
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setTag:NSIntegerMin];
[toolbar sizeToFit];
toolbar.tag = NSIntegerMin; // mark it so as to differentiate with user's accessoryViews, if any.

// Create a fake button to maintain flexibleSpace between doneButton and nilButton. (Actually it moves done button to right side.
UIBarButtonItem *nilButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
Expand All @@ -890,9 +941,9 @@ -(void)addDoneOnKeyboardWithTarget:(id)target action:(SEL)action
{
[toolbar setBarStyle:UIBarStyleBlackTranslucent];
}
// Adding button to toolBar.
[toolbar setItems:[NSArray arrayWithObjects: nilButton,doneButton, nil]];
[toolbar setItems:[NSArray arrayWithObjects: nilButton, doneButton, nil]];

// Setting toolbar to textFieldPhoneNumber keyboard.
[(UITextField*)self setInputAccessoryView:toolbar];
Expand All @@ -907,6 +958,7 @@ -(void)addCancelDoneOnKeyboardWithTarget:(id)target cancelAction:(SEL)cancelActi
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setTag:NSIntegerMin];
[toolbar sizeToFit];
toolbar.tag = NSIntegerMin; // mark it so as to differentiate with user's accessoryViews, if any.

// Create a cancel button to show on keyboard to resign it. Adding a selector to resign it.
UIBarButtonItem *cancelButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:target action:cancelAction];
Expand Down Expand Up @@ -943,7 +995,8 @@ -(void)addPreviousNextDoneOnKeyboardWithTarget:(id)target previousAction:(SEL)pr
UIToolbar *toolbar = [[UIToolbar alloc] init];
[toolbar setTag:NSIntegerMin];
[toolbar sizeToFit];

toolbar.tag = NSIntegerMin; // mark it so as to differentiate with user's accessoryViews, if any.

NSMutableArray *items = [[NSMutableArray alloc] init];

// Create a done button to show on keyboard to resign it. Adding a selector to resign it.
Expand Down