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

fix: ios 14 Bug #2097

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
16 changes: 6 additions & 10 deletions Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -2444,10 +2444,9 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = "$(inherited)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7UUTF6T5P9;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "";
Expand All @@ -2457,7 +2456,7 @@
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = NO;
INFOPLIST_FILE = Demo/Objective_C_Demo/Resources/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -2467,7 +2466,6 @@
PRODUCT_NAME = IQKeyboardManagerDemo;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = infoenumapps;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
Expand All @@ -2490,10 +2488,9 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = "$(inherited)";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7UUTF6T5P9;
GCC_C_LANGUAGE_STANDARD = c99;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "";
Expand All @@ -2503,7 +2500,7 @@
GCC_WARN_UNUSED_LABEL = YES;
GCC_WARN_UNUSED_PARAMETER = NO;
INFOPLIST_FILE = Demo/Objective_C_Demo/Resources/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -2513,7 +2510,6 @@
PRODUCT_NAME = IQKeyboardManagerDemo;
PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = infoenumapps;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
Expand Down
256 changes: 136 additions & 120 deletions IQKeyboardManager/IQKeyboardManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -1365,10 +1365,9 @@ - (void)reloadLayoutIfNeeded

#pragma mark - UIKeyboard Notification methods
/* UIKeyboardWillShowNotification. */
-(void)keyboardWillShow:(NSNotification*)aNotification
{
-(void) c_keyboardWillShow:(NSNotification*)aNotification{
_kbShowNotification = aNotification;
// Boolean to know keyboard is showing/hiding
_keyboardShowing = YES;

Expand Down Expand Up @@ -1403,7 +1402,7 @@ -(void)keyboardWillShow:(NSNotification*)aNotification
_topViewBeginSafeAreaInsets = UIEdgeInsetsZero;
return;
}
CFTimeInterval startTime = CACurrentMediaTime();
[self showLog:[NSString stringWithFormat:@">>>>> %@ started >>>>>",NSStringFromSelector(_cmd)] indentation:1];

Expand Down Expand Up @@ -1447,128 +1446,145 @@ -(void)keyboardWillShow:(NSNotification*)aNotification
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
[self showLog:[NSString stringWithFormat:@"<<<<< %@ ended: %g seconds <<<<<",NSStringFromSelector(_cmd),elapsedTime] indentation:-1];
}
-(void)keyboardWillShow:(NSNotification*)aNotification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self c_keyboardWillShow:aNotification];
});

}

/* UIKeyboardWillHideNotification. So setting rootViewController to it's default frame. */

- (void)c_keyboardWillHide:(NSNotification*)aNotification{

if (aNotification) _kbShowNotification = nil;

// Boolean to know keyboard is showing/hiding
_keyboardShowing = NO;

// Getting keyboard animation duration
CGFloat duration = [[aNotification userInfo][UIKeyboardAnimationDurationUserInfoKey] floatValue];
if (duration!= 0.0f)
{
_animationDuration = duration;
}
else
{
_animationDuration = 0.25;
}

//If not enabled then do nothing.
if ([self privateIsEnabled] == NO) return;

CFTimeInterval startTime = CACurrentMediaTime();
[self showLog:[NSString stringWithFormat:@">>>>> %@ started >>>>>",NSStringFromSelector(_cmd)] indentation:1];

[self showLog:[NSString stringWithFormat:@"Notification Object: %@", NSStringFromClass([aNotification.object class])]];

//Commented due to #56. Added all the conditions below to handle WKWebView's textFields. (Bug ID: #56)
// We are unable to get textField object while keyboard showing on WKWebView's textField. (Bug ID: #11)
// if (_textFieldView == nil) return;

//Restoring the contentOffset of the lastScrollView
__strong __typeof__(UIScrollView) *strongLastScrollView = _lastScrollView;

if (strongLastScrollView)
{
__weak __typeof__(self) weakSelf = self;
__weak __typeof__(UIView) *weakTextFieldView = self.textFieldView;

[UIView animateWithDuration:_animationDuration delay:0 options:(_animationCurve|UIViewAnimationOptionBeginFromCurrentState) animations:^{

__strong __typeof__(self) strongSelf = weakSelf;
__strong __typeof__(UIView) *strongTextFieldView = weakTextFieldView;

if (UIEdgeInsetsEqualToEdgeInsets(strongLastScrollView.contentInset, strongSelf.startingContentInsets) == NO)
{
[strongSelf showLog:[NSString stringWithFormat:@"Restoring ScrollView contentInset to : %@",NSStringFromUIEdgeInsets(strongSelf.startingContentInsets)]];

strongLastScrollView.contentInset = strongSelf.startingContentInsets;
strongLastScrollView.scrollIndicatorInsets = strongSelf.startingScrollIndicatorInsets;
}

if (strongLastScrollView.shouldRestoreScrollViewContentOffset && CGPointEqualToPoint(strongLastScrollView.contentOffset, strongSelf.startingContentOffset) == NO)
{
[strongSelf showLog:[NSString stringWithFormat:@"Restoring ScrollView contentOffset to : %@",NSStringFromCGPoint(strongSelf.startingContentOffset)]];

// (Bug ID: #1365, #1508, #1541)
UIStackView *stackView = [strongTextFieldView superviewOfClassType:[UIStackView class] belowView:strongLastScrollView];
BOOL animatedContentOffset = stackView != nil || [strongLastScrollView isKindOfClass:[UICollectionView class]];

if (animatedContentOffset)
{
[strongLastScrollView setContentOffset:strongSelf.startingContentOffset animated:UIView.areAnimationsEnabled];
}
else
{
strongLastScrollView.contentOffset = strongSelf.startingContentOffset;
}
}

// TODO: restore scrollView state
// This is temporary solution. Have to implement the save and restore scrollView state
UIScrollView *superScrollView = strongLastScrollView;
do
{
CGSize contentSize = CGSizeMake(MAX(superScrollView.contentSize.width, CGRectGetWidth(superScrollView.frame)), MAX(superScrollView.contentSize.height, CGRectGetHeight(superScrollView.frame)));

CGFloat minimumY = contentSize.height-CGRectGetHeight(superScrollView.frame);

if (minimumY<superScrollView.contentOffset.y)
{
CGPoint newContentOffset = CGPointMake(superScrollView.contentOffset.x, minimumY);
if (CGPointEqualToPoint(superScrollView.contentOffset, newContentOffset) == NO)
{
[self showLog:[NSString stringWithFormat:@"Restoring contentOffset to : %@",NSStringFromCGPoint(newContentOffset)]];

// (Bug ID: #1365, #1508, #1541)
UIStackView *stackView = [strongSelf.textFieldView superviewOfClassType:[UIStackView class] belowView:superScrollView];
BOOL animatedContentOffset = stackView != nil || [superScrollView isKindOfClass:[UICollectionView class]];

if (animatedContentOffset)
{
[superScrollView setContentOffset:newContentOffset animated:UIView.areAnimationsEnabled];
}
else
{
superScrollView.contentOffset = newContentOffset;
}
}
}
}
while ((superScrollView = (UIScrollView*)[superScrollView superviewOfClassType:[UIScrollView class]]));

} completion:NULL];
}

[self restorePosition];

//Reset all values
_lastScrollView = nil;
_kbFrame = CGRectZero;
[self notifyKeyboardSize:_kbFrame.size];
_startingContentInsets = UIEdgeInsetsZero;
_startingScrollIndicatorInsets = UIEdgeInsetsZero;
_startingContentOffset = CGPointZero;
_topViewBeginOrigin = kIQCGPointInvalid;
_topViewBeginSafeAreaInsets = UIEdgeInsetsZero;

CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
[self showLog:[NSString stringWithFormat:@"<<<<< %@ ended: %g seconds <<<<<",NSStringFromSelector(_cmd),elapsedTime] indentation:-1];
}

- (void)keyboardWillHide:(NSNotification*)aNotification
{
//If it's not a fake notification generated by [self setEnable:NO].
if (aNotification) _kbShowNotification = nil;

// Boolean to know keyboard is showing/hiding
_keyboardShowing = NO;

// Getting keyboard animation duration
CGFloat duration = [[aNotification userInfo][UIKeyboardAnimationDurationUserInfoKey] floatValue];
if (duration!= 0.0f)
{
_animationDuration = duration;
}
else
{
_animationDuration = 0.25;
}

//If not enabled then do nothing.
if ([self privateIsEnabled] == NO) return;

CFTimeInterval startTime = CACurrentMediaTime();
[self showLog:[NSString stringWithFormat:@">>>>> %@ started >>>>>",NSStringFromSelector(_cmd)] indentation:1];

[self showLog:[NSString stringWithFormat:@"Notification Object: %@", NSStringFromClass([aNotification.object class])]];

//Commented due to #56. Added all the conditions below to handle WKWebView's textFields. (Bug ID: #56)
// We are unable to get textField object while keyboard showing on WKWebView's textField. (Bug ID: #11)
// if (_textFieldView == nil) return;

//Restoring the contentOffset of the lastScrollView
__strong __typeof__(UIScrollView) *strongLastScrollView = _lastScrollView;

if (strongLastScrollView)
{
__weak __typeof__(self) weakSelf = self;
__weak __typeof__(UIView) *weakTextFieldView = self.textFieldView;

[UIView animateWithDuration:_animationDuration delay:0 options:(_animationCurve|UIViewAnimationOptionBeginFromCurrentState) animations:^{

__strong __typeof__(self) strongSelf = weakSelf;
__strong __typeof__(UIView) *strongTextFieldView = weakTextFieldView;

if (UIEdgeInsetsEqualToEdgeInsets(strongLastScrollView.contentInset, strongSelf.startingContentInsets) == NO)
{
[strongSelf showLog:[NSString stringWithFormat:@"Restoring ScrollView contentInset to : %@",NSStringFromUIEdgeInsets(strongSelf.startingContentInsets)]];

strongLastScrollView.contentInset = strongSelf.startingContentInsets;
strongLastScrollView.scrollIndicatorInsets = strongSelf.startingScrollIndicatorInsets;
}

if (strongLastScrollView.shouldRestoreScrollViewContentOffset && CGPointEqualToPoint(strongLastScrollView.contentOffset, strongSelf.startingContentOffset) == NO)
{
[strongSelf showLog:[NSString stringWithFormat:@"Restoring ScrollView contentOffset to : %@",NSStringFromCGPoint(strongSelf.startingContentOffset)]];

// (Bug ID: #1365, #1508, #1541)
UIStackView *stackView = [strongTextFieldView superviewOfClassType:[UIStackView class] belowView:strongLastScrollView];
BOOL animatedContentOffset = stackView != nil || [strongLastScrollView isKindOfClass:[UICollectionView class]];

if (animatedContentOffset)
{
[strongLastScrollView setContentOffset:strongSelf.startingContentOffset animated:UIView.areAnimationsEnabled];
}
else
{
strongLastScrollView.contentOffset = strongSelf.startingContentOffset;
}
}

// TODO: restore scrollView state
// This is temporary solution. Have to implement the save and restore scrollView state
UIScrollView *superScrollView = strongLastScrollView;
do
{
CGSize contentSize = CGSizeMake(MAX(superScrollView.contentSize.width, CGRectGetWidth(superScrollView.frame)), MAX(superScrollView.contentSize.height, CGRectGetHeight(superScrollView.frame)));

CGFloat minimumY = contentSize.height-CGRectGetHeight(superScrollView.frame);

if (minimumY<superScrollView.contentOffset.y)
{
CGPoint newContentOffset = CGPointMake(superScrollView.contentOffset.x, minimumY);
if (CGPointEqualToPoint(superScrollView.contentOffset, newContentOffset) == NO)
{
[self showLog:[NSString stringWithFormat:@"Restoring contentOffset to : %@",NSStringFromCGPoint(newContentOffset)]];

// (Bug ID: #1365, #1508, #1541)
UIStackView *stackView = [strongSelf.textFieldView superviewOfClassType:[UIStackView class] belowView:superScrollView];
BOOL animatedContentOffset = stackView != nil || [superScrollView isKindOfClass:[UICollectionView class]];

if (animatedContentOffset)
{
[superScrollView setContentOffset:newContentOffset animated:UIView.areAnimationsEnabled];
}
else
{
superScrollView.contentOffset = newContentOffset;
}
}
}
}
while ((superScrollView = (UIScrollView*)[superScrollView superviewOfClassType:[UIScrollView class]]));

} completion:NULL];
}
dispatch_async(dispatch_get_main_queue(), ^{
[self c_keyboardWillHide:aNotification];
});

[self restorePosition];

//Reset all values
_lastScrollView = nil;
_kbFrame = CGRectZero;
[self notifyKeyboardSize:_kbFrame.size];
_startingContentInsets = UIEdgeInsetsZero;
_startingScrollIndicatorInsets = UIEdgeInsetsZero;
_startingContentOffset = CGPointZero;
_topViewBeginOrigin = kIQCGPointInvalid;
_topViewBeginSafeAreaInsets = UIEdgeInsetsZero;

CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
[self showLog:[NSString stringWithFormat:@"<<<<< %@ ended: %g seconds <<<<<",NSStringFromSelector(_cmd),elapsedTime] indentation:-1];

}

-(void)registerKeyboardSizeChangeWithIdentifier:(nonnull id<NSCopying>)identifier sizeHandler:(void (^_Nonnull)(CGSize size))sizeHandler
Expand Down
2 changes: 1 addition & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -90,4 +90,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: e614b88580b21d28b61be6f469e20fbe893f1525

COCOAPODS: 1.16.0
COCOAPODS: 1.15.2