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];
}];
}
Related
I have a screen within an iPhone app that consist of a UITextView. This text view is contained within a UIScrollView. The purpose of the screen is for the user to type in text, and to optionally attach an image to what he is writing. Therefore, the screen also has a UIToolbar with a camera button at the bottom of the screen. The structure of the screen is as follows:
-View
--UIScrollView
---UITextView
--UIToolbar
---UIButton
When the user navigates to this screen, the viewDidAppear method assigns first responder to the uitextview element, so the keyboard shows up, which hides the toolbar and the camera button.
I would like the entire toolbar to re-draw itself right above the keyboard, and to position itself again at the bottom of the screen when the keyboard hides.
I have found related posts on SO (like this one). However, such methods introduce undesired behaviours. For example, implementing the solution in the article above, the toolbar does move with the keyboard, but the UIScrollView gets its frame.origin.y coordinate shifted way above the top of the screen, so it's impossible for the user to see what he is typing.
I have also tried to reset the frame of the toolbar, by adding it as an IBOutlet and using cgrectmake to reposition it. However, after several tries, the toolbar remains stuck at the bottom of the screen and hidden by the keyboard:
- (void) liftMainViewWhenKeybordAppears:(NSNotification*)aNotification{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.3];
[UIView setAnimationCurve:<#(UIViewAnimationCurve)#>]
CGRect frame = self.keyboardToolbar.frame;
frame.origin.y = self.keyboardToolbar.frame.origin.y - 280;
self.keyboardToolbar.frame = frame;
[UIView commitAnimations];
}
I have tried several iterations similar to the code above and they all fail at repositioning the toolbar.
So in short, what is the right way to float a toolbar right on top of a keyboard in a screen whose space is completely utilised by a uitextview element?
Thanks to RoryMcKinnel for the pointer. As the article referenced is in Swift, I thought I might paste the solution that worked for be on ObjC
- (void)keyboardWillShowNotification:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
double animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardEndFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect convertedKeyboardFrame = [self.view convertRect:keyboardEndFrame fromView:self.view.window];
UIViewAnimationOptions rawAnimationCurve = (UIViewAnimationOptions)[userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
_toolBarBottomGuide.constant = CGRectGetMaxY(self.view.bounds) - CGRectGetMinY(convertedKeyboardFrame);
[UIView animateWithDuration:animationDuration delay:0.0 options:rawAnimationCurve animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
Bear in mind, this code did make the toolbar move as required, but the toolbar was not visible at all. It turned out that it was being hidden behind the UIScrollView. This was easily fixed by shifting the order between the scroll view and the toolbar element in the IB hierarchy.
The method above works for the keyboardWillShow event. You'll need to add the corresponding one for when the keyboard hides, like this:
- (void)keyboardWillHideNotification:(NSNotification *)notification{
NSDictionary *userInfo = notification.userInfo;
double animationDuration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect keyboardEndFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
UIViewAnimationOptions rawAnimationCurve = (UIViewAnimationOptions)[userInfo[UIKeyboardAnimationCurveUserInfoKey] unsignedIntegerValue] << 16;
_toolBarBottomGuide.constant = 0.0f;
[UIView animateWithDuration:animationDuration delay:0.0 options:rawAnimationCurve animations:^{
[self.view layoutIfNeeded];
} completion:nil];
}
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.
This code was working beautifully in ios 7. However, with ios8 and xcode 6.0.1 it has stopped working. When a user clicked on a text field to enter text, the field animated to float just above the top of the keyboard so they can see what they are typing. Any thoughts on why this fails to work now. I can see it start to animate for a split second, but then the textfield disappears. Frustrating.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.4];
[UIView setAnimationBeginsFromCurrentState:YES];
textField.frame = CGRectMake(textField.frame.origin.x, (textField.frame.origin.y - 200.0),
textField.frame.size.width, textField.frame.size.height);
_searchBtn.frame = CGRectMake(_searchBtn.frame.origin.x, (_searchBtn.frame.origin.y - 200.0),
_searchBtn.frame.size.width, _searchBtn.frame.size.height);
[UIView commitAnimations];
textField.alpha = .75;
}
The problem is that your code adjusts your TextField's position by a fixed value of 200.0
This was probably great for iOS7 but things have changed in iOS8 for two reasons:
The system keyboard has an additional view for showing predicted words while typing
Custom keyboards can be as high as the developer chooses
You need to change your approach move moving the location of your TextField whenever the keyboard is shown or hidden using the following two notifications:
UIKeyboardWillShowNotification
UIKeyboardWillHideNotification
In the following thread I explain the problems that can arise and how to properly move your views around as the keyboard opens:
can't get correct value of keyboard height in iOS8
EDIT 1:
Assuming the textbox has an outlet called "yourTextBox", the code to modify the position of your textbox could look something like:
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
CGFloat keyboardHeight = <<calculated keyboard height as previously discussed>>;
CGFloat textBoxHeight = _yourTextBox.frame.size.height;
// Change the current frame of your textbox in order to reposition it
CGFrame textBoxFrame = _yourTextBox.frame;
textBoxFrame.origin.y = screenHeight - keyboardHeight - textBoxHeight;
_yourTextBox.frame = textBoxFrame;
Note: If you are using AutoLayout constraints to position your subviews you will need to avoid modifying the frame and change your constraints instead. Post if you are having problems in this area because it can get tricky.
I am developing a chat app which has UITableView and a UIView containing a UITextField and a UIButton in it. I am using the following code to move the UIView up when keyboard appears.
(void)keyboardWillShow:(NSNotification *)notification
{
NSDictionary* info = [notification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
[UIView animateWithDuration:0.2f animations:^{
CGRect frame = self.inputView.frame;
UIInterfaceOrientation orientation = self.interfaceOrientation;
if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight)
frame.origin.y -= kbSize.width;
else
frame.origin.y -= kbSize.height;
self.inputView.frame = frame;
;
}];
}
This code is working fine until iOS 7, but in iOS 8 UIView is not displaying above the keyboard.
Can anyone please suggest what could be the possible issue, or is there anything that has changed in iOS 8?
Your code seems to be correct but i will prefer using UIKeyboardDidChangeFrameNotification or UIKeyboardWillChangeFrameNotification because these will tell you the change in keyboard frame when predictive text bar gets up or down when keyboard is in view.
In your ViewDidLoad add this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameDidChange:)
name:UIKeyboardDidChangeFrameNotification object:nil];
and then paste this method in your ViewController
-(void)keyboardFrameDidChange:(NSNotification*)notification{
NSDictionary* info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
[yourView setFrame:CGRectMake(0, kKeyBoardFrame.origin.y-yourView.frame.size.height, 320, yourView.frame.size.height)];
}
This will handle all your keyboard cases like when its up or down or change in its frame with predictive text bar
and also remove observer when you are leaving your view
The accepted Answer is almost right. To match your view's animation to that of the keyboard you want to use the UIKeyboardWillChangeFrameNotification rather than the UIKeyboardDidChangeFrameNotification. That way the animations you kick off will precisely match that of the keyboard. Here's some code to do the entire thing. I use the animation of the keyboard to drive the animation of my autolayout constraint constants, but you can easily adapt this to animate an entire view frame. (Note, we have to use the old school style animations to hook into the UIKeyboardCurveInfoKey which provides an animation curve exactly matching the keyboard animation.
In viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardFrameDidChange:)
name:UIKeyboardWillChangeFrameNotification
object:nil];
In ViewController:
- (void)keyboardFrameDidChange:(NSNotification *)notification {
NSDictionary *info = [notification userInfo];
CGRect kKeyBoardFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGFloat height = kKeyBoardFrame.size.height;
[self.view removeConstraints:self.verticalButtonConstraints];
NSDictionary *metrics = #{#"height" : #(height)};
NSDictionary *views = #{#"nextButton" : self.nextButton};
self.verticalButtonConstraints = [NSLayoutConstraint constraintsWithVisualFormat:#"V: [nextButton(52)]-(height)-|" options:0 metrics:metrics views:views];
[self.view addConstraints:self.verticalButtonConstraints];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:[notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
[UIView setAnimationCurve:[notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]];
[UIView setAnimationBeginsFromCurrentState:YES];
[self.view layoutIfNeeded];
[UIView commitAnimations];
}
I just ran into this and made a discovery I thought I would share. In iOS 8 layout passes for the sub views of the main view will be done whenever the keyboard is about to appear or about to go away. These passes do not get done on iOS 7. So if you try to animate a sub view of the main view in keyBoardWillShow or keyboardWillChangeFrame the animation will get undone by the layout pass and your sub views that you tried to animate will move back to their original position. That is why keyboardDidChangeFrame works to animate the subviews and keyboardWillChangeFrame does not.
Something odd I noted as well is the timing of when these calls are made. It seems the first time that the keyboard appears after the app is launched, the call to keyboardDidChangeFrame happens too late to be able to animate with the keyboard so they slide up together, but on second and subsequent times the keyboard shows, the call to keyboardDidChangeFrame happens sooner and it seems you can actually animate the views along with the keyboard.
I must note that I am using C# and Xamarin as my development platform for iOS, so this may be different when using Swift or Obj-C.
You can use an accessoryView, which will attach itself to the top of the keyboard. Alternatively, if you want more power over customization, you can use notifications as explained by #pankaj_wadwha to fetch the frame information. Bonus: you can also get the animation information (such as speed) so your view moves alongside the keyboard perfectly.
Im curious about a feature in iOS. Please help me out here if you can.
Scenario: I am using a text box where name is entered. Its on lower half of the screen. Just below the text box is a label which displays the number of characters remaining(e.g.like in a twitter feed).
Problem: When i place the text box in upper half of the screen. both the text field and label are visible. But when I place them in lower half, the apple keyboard covers the label part.
Is there a way where I control the area covered in such a way that the label below is also visible?
I hope I have made myself clear enough.
Thanks.
Here i have used delegate method for UITextView Same way you can do for UITextField
-Here in this code when user starts entering values in textview it makes your view's hight lesser then its original with animation
-When user Ends Entering values, it will make your view's size original size.
-(void)textViewDidBeginEditing:(UITextView *)textView
{
CGRect frame = self.view.frame;
frame.origin.y = -100;
[self.view setFrame:frame];
[UIView commitAnimations];
}
-(void)textViewDidEndEditing:(UITextView *)textView
{
CGRect frame = self.view.frame;
frame.origin.y = 0;
[self.view setFrame:frame];
[UIView commitAnimations];
}
If you want to know about delegates this link helps you
Well in that case you have to move the textbox when the keyboard pops up.You can have the notification registered to know when the keyboard pops up and a scrollview to scroll the whole content up the screen can do the job for you
See this question,It explains well how to manage something like this
AFAIK You can't control the size of iOS native Keyboard, all you can and should be doing is, making them a subivew of a scroll view and scroll it up.
So the usual practice go something like this.
Subscribe to the Keyboard notification. UIKeyboardWillShowNotification
In the method which the Notification listener will be invoking, set the scrollView's content size accordingly and set the content offset.
self.scrollView.contentSize = CGSizeMake(320, 267);
self.scrollView.contentInset = UIEdgeInsetsMake(0, 0, localKeyboardFrame.size.height, 0);
[self.scrollView scrollRectToVisible:<rect of view you want to scroll to> animated:YES];
Undo the changes when the keyboard hides, with the help of appropriate notification.UIKeyboardWillHideNotification
self.scrollView.contentInset = UIEdgeInsetsZero
And here is iOS Human Interface Guide's explanation on it.
Add following to your viewDidLoad Method
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(showKeyboard) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(hideKeyboard) name:UIKeyboardWillHideNotification object:nil];
And after that-- Declare the following 2 methods in your .m file
-(void)showKeyboard {
[UIView beginAnimations:#"slide" context:nil];
[UIView setAnimationDuration:0.3];
self.view.transform = CGAffineTransformMakeTranslation(0, -100);
[UIView commitAnimations]; }
-(void)hideKeyboard {
[UIView beginAnimations:#"slide" context:nil];
[UIView setAnimationDuration:0.1];
self.view.transform = CGAffineTransformMakeTranslation(0, 0);
[UIView commitAnimations]; }