UIKeyboardWillShowNotification issues with ios 11 beta 7 - ios

Testing my app on iOS 11 beta 7 - it seems like the keyboard doesn't push up the content if my UIViewController.
The code looks like this (working since iOS7):
- (void)handleNotification:(NSNotification*)notification {
if (notification.name == UIKeyboardWillShowNotification) {
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
nextButtonALBottomDistance.constant = keyboardSize.height + initialPhoneBottomDistance;
codeBottomViewALBottomDistance.constant = keyboardSize.height + initialCodeBottomDistance;
double animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
else if (notification.name == UIKeyboardWillHideNotification) {
nextButtonALBottomDistance.constant = initialPhoneBottomDistance;
codeBottomViewALBottomDistance.constant = initialCodeBottomDistance;
double animationDuration = [[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
[UIView animateWithDuration:animationDuration animations:^{
[self.view layoutIfNeeded];
}];
}
}
Interesting enough - when I press the home button (minimizing the app) and reopening it (without killing it) - the layout is fixed.
It seems like an iOS 11 beta bug, but I couldn't find any reference to it so far.
Happy to know if someone else is having this issue.

Use UIKeyboardFrameEndUserInfoKey because that key is for the NSValue object containing a CGRect that identifies an end frame of the keyboard in screen coordinates. Do not use UIKeyboardFrameBeginUserInfoKey.

If you are using UIKeyboardFrameBeginUserInfoKey key for getting keyboard height, replace it with UIKeyboardFrameEndUserInfoKey to get the correct keyboard height.
In iOS 11, height value of the frame for UIKeyboardFrameBeginUserInfoKey key is 0 because it is a start frame. To get the actual height we need the end frame, and end frame is returned by UIKeyboardFrameEndUserInfoKey.
Please refer Managing the Keyboard documentation:
UIKeyboardFrameBeginUserInfoKey The
key for an NSValue object containing a
CGRect that identifies the start frame
of the keyboard in screen coordinates.
These coordinates do not take into
account any rotation factors applied
to the window’s contents as a result
of interface orientation changes.
Thus, you may need to convert the
rectangle to window coordinates (using
the convertRect:fromWindow: method) or
to view coordinates (using the
convertRect:fromView: method) before
using it.
UIKeyboardFrameEndUserInfoKey The key
for an NSValue object containing a
CGRect that identifies the end frame
of the keyboard in screen coordinates.
These coordinates do not take into
account any rotation factors applied
to the window’s contents as a result
of interface orientation changes.
Thus, you may need to convert the
rectangle to window coordinates (using
the convertRect:fromWindow: method) or
to view coordinates (using the
convertRect:fromView: method) before
using it.

I ran into this non-movement issue as well. I suspect that the beginning & end frame were always incorrect, in that they were the same or nearly the same, but was fixed recently in iOS 11 and as such broke a lot of code that didn't truly understand the different between these two frames.
Based on the information here
https://stackoverflow.com/a/14326257/5282052
Begin is what the keyboard starts off looking like, which most won't want.
End is the result of what the keyboard will look like, which most only are concerned with.
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size;
Does indeed resolve my issue with a ZERO movement of the scrollview.

Related

The height on my soft keyboard changes when triggered multiple times

I have an observed method that trigger when the soft keyboard is shown. It works fine, but for some reason the height of the soft keyboard changes after it has been hidden, then presented for the second time. I can't find a reason for this and there doesn't seem to be anything in the hide-delegate that changes its value. What causes this? I have worked around the problem by storing the height then using it the second time, but I would like to know the cause of this issue.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize keyboardSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
CGRect visibleRect = self.view.frame;
if (_storedKeyboardHeight.size.height == 0) {
_storedKeyboardHeight.size.height = keyboardSize.height;
}
visibleRect.size.height = _storedKeyboardHeight.size.height;
visibleRect.origin.y = self.view.height - visibleRect.size.height;
CGRect rectOfCellInTableView = [self.loginTableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:1]];
//This changes the second time
NSLog(#"🦁 %f", keyboardSize.height);
//so I store the original value here
NSLog(#"🦁 %#", CGRectCreateDictionaryRepresentation(_storedKeyboardHeight));
if ((rectOfCellInTableView.origin.y + rectOfCellInTableView.size.height) > visibleRect.origin.y){
CGPoint scrollPoint = CGPointMake(0.0, (rectOfCellInTableView.origin.y + rectOfCellInTableView.size.height) - visibleRect.origin.y + 50);
[self.loginTableView setContentOffset:scrollPoint animated:YES];
}
}
First time the height is 291, second time it's 233.
The problem is that you are examining the wrong frame:
UIKeyboardFrameBeginUserInfoKey
When the keyboard is shown, what its frame height is at the beginning of the showing process is of no interest to you. What you want to know is the frame at the end of the showing process:
UIKeyboardFrameEndUserInfoKey
Also, it looks like you are getting notified of the wrong thing. You have not shown what notification you are registered for, but the name of your method, keyboardWasShown, suggests that your are getting notified when the keyboard did show. That's too late; this notification is almost never of any interest. You want to know when the keyboard will show.

Adjusting view frame for iOS hardware keyboard

I followed the instructions here to adjust my view with the iOS keyboard.
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
This doesn't work with a hardware keyboard. When a text view is active the iOS keyboard is not shown but the example code still returns the full height of the keyboard. In my case just the input accessory view is shown on the screen.
How do I detect this case and adjust my view for only the input accessory view?
You can intersect the keyboard's frame with the current window as in my answer here https://stackoverflow.com/a/36553555/1049134.
Came across the same issue.
Looks like the iOS keyboard is completely instantiated and just moved out of the view partial when a hardware keyboard is attached. Therefore the size of the keyboard is right. It is just not completely shown.
After examining the notifications I solved it with calculating the visible keyboard height myself.
In my example I am listening to UIKeyboardWillShowNotification, UIKeyboardWillChangeFrameNotification and UIKeyboardWillHideNotification.
-(void)keyboardMessage:(NSNotification*)notification {
NSDictionary *userInfo = notification.userInfo;
CGFloat duration = [userInfo[#"UIKeyboardAnimationDurationUserInfoKey"] floatValue];
NSValue *value = userInfo[#"UIKeyboardFrameEndUserInfoKey"];
CGRect frame = [value CGRectValue];
[UIView animateWithDuration:duration animations:^{
self.lowerContraint.constant = self.view.frame.size.height - frame.origin.y;;
[self.view needsUpdateConstraints];
[self.view layoutIfNeeded];
}];
}

Animating view on UIKeyboardWillShowNotification event in iOS 8

I am using following code to animate view's position according to keyboard movement. The code works fine under iOS 7, however it causes strange behaviour under iOS 8:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
- (void) keyboardWillShow:(NSNotification*) aNotification {
NSDictionary* keyboardInfo = [aNotification userInfo];
NSTimeInterval time = [keyboardInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [keyboardInfo[UIKeyboardAnimationCurveUserInfoKey] intValue];
CGRect keyboardFrameEnd = [[keyboardInfo valueForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
double offset = keyboardFrameEnd.size.width > keyboardFrameEnd.size.height ? keyboardFrameEnd.size.height : keyboardFrameEnd.size.width;
[UIView beginAnimations:#"moveWindow" context:nil];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationCurve:curve];
[UIView setAnimationDuration:time];
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + offset, self.frame.size.width, self.frame.size.height);
[UIView commitAnimations];
}
Unfortunately, the answers mentioned in Is there a change to the behaviour of UIKeyboardWillShowNotification in iOS 8? and iOS8: What's going on with moving views during keyboard transitions? are out of the question:
The source code base is very large and old and use neither storyboard nor Auto Layout features.
I don't want to use UIKeyboardDidShowNotification event because the keyboard is already visible and the animation looks terrible (however, the problem is gone when using this type of notification).
Oddly enough, I found out that the problem is gone when the feature is used in the very first screen of the application. Further tests showed that removing MKMapView from one of the previous screens solves this issue. I triple checked that MKMapView is used and disposed correctly. Every allocated instance is gone way before the above code is executed.
After hours of testing and debugging I noticed in a visual hierarchy debugger (How do I inspect the view hierarchy in iOS?) that there are constraints added under UILayoutContainerView and UINavigationTransitionView. These constraints are not present when the MKMapView control is removed from the previous screen. I tried playing with every possible combination of setTranslatesAutoresizingMaskIntoConstraints: setup and could not find any resolution yet. Is it some sort of bug in iOS 8 itself or is there another way to animate view along with the keyboard?
I'm not sure about the code itself but from the documentation about those animation methods...
Use of this method is discouraged in iOS 4.0 and later. You should use the block-based animation methods to specify your animations instead.
The correct way to animate you view is...
[UIView animateWithDuration:time
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y + offset, self.frame.size.width, self.frame.size.height);
}
completion:nil];
Edit
OK, it's not AutoLayout (I think) but I'll leave this here anyway as you need to change it and I'll wait for more information in the question.

ios keyboardwillshow notification firing late

I am experiencing a strange error on iOS 8 when trying to synchronize an animation in tandem with the keyboard moving up after selecting a textfield.
Specifically, I am trying to get the height of the keyboard in order to know how far up to move the text field by using the following code after registering for the keyboardwillshow notification:
- (void)keyboardWillShow:(NSNotification *)notification
{
CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
self.keyboardHeight = keyboardSize.height;
[self moveToolbarUp];
}
-(void)moveToolbarUp
{
self.keyboardExpanded = YES;
CGRect frame = self.toolbar.frame;
DLog(#"keyboard height now:%f",self.keyboardHeight);
frame.origin.y = (self.view.frame.size.height-toolbarHeight-self.keyboardHeight);
[UIView animateWithDuration:0.1 animations:^{
self.toolbar.frame = frame;
}];
}
However, if I try to set a break point at the keyboardwillshow method, I can see that the keyboard is already all the way up when the method is called, and the animation is therefore delayed (the keyboard pops up and then a second or so later, the textfield follows).
Has anybody else experienced this error? I am running on an iPhone 5s, iOS 8.0.2.
Thanks!!
It's not an error. The fact is that you can remove your animateWithDuration call. In iOS 8, keyboardWillShow: is called inside the keyboard's animation. You don't have to synchronize anything; anything you do will be part of the animation, automatically.

Take CGRect out of UITextView

This must sound really weird but I want to take the keyboard's CGRect and take it out of the UITextView. Here is a picture to help:
I basically want the UITextView to become smaller so when I add text it scrolls down. If you need more info ask me.
EDIT: When I use this code:
- (void)keyboardWasShown:(NSNotification*)notification {
NSDictionary* info = [notification userInfo];
kbSIZE = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
CGRect newTextViewFrame = self.notesTextView.frame;
newTextViewFrame.size.height -= kbSIZE.size.height;
self.notesTextView.frame = newTextViewFrame;
}
this happens:
Not that weird at all. The same thing often happens with tableviews when you are bringing up a keyboard. This bit of code should help.
CGRect newTextViewFrame = textView.frame;
newTextFrame.size.height -= keyboardSize.frame.size.height;
textView.frame = newScrollFrame;
This is not weird at all :)
You can do this by registering as an observer to the UIKeyboardWillShowNotification (it would be a good idea to also register for the UIKeyboardWillHideNotification in the same process).
When the registered selector will be called, the notification parameter will contain the keyboard's size inside the UIKeyboardFrameEndUserInfoKey value of the userInfo dictionnary :
[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size
All you need to do now is to set the frame of your UITextView to your desired size.
Be warned : the CGRect you get does not take into account the device orientation. This means, if the device is in fact in landscape mode, you'll need to switch the width and height of the CGRect for it to make sense in your context.

Resources