Right now I'm trying to write a function to moving up frame when keyboard appears on the screen.
I started to use NSNNotificationCenter. My code is working but not correctly. When keyboard appears my formView is moving up but when I start to edit next textField in formView, formView is moving up again. What's wrong with my code?
Thanks.
- (void)keyboardWillShow:(NSNotification *) aNotification {
NSDictionary *userInfo = [aNotification userInfo];
CGRect frame = self.formView.frame;
frame.origin.y -= 170;
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
formView.frame = frame;
[UIView commitAnimations];
}
You should add again your 170 pixels (or whatever you calculate as suggested by Mike) to the origin.y of your view when the keyboard is disappearing. When you click on another text field, technically the current keyboard will disappear (your view does not react in any way) and a new keyboard will appear (your keyboardWillShow will be called again and you shift your view again up by 170 px).
Related
I have registered for notifications of Keyboard showing and Hiding.
The text View is scrollable when not clicked on it.. i.e. when it is not in editable mode..
When user click .. i update its frame to come up ..and after that it doesn't scroll.. after ending editing.. i change its position back its scrollable again..
Here is my code
- (void)keyboardWillHide:(NSNotification *)n
{
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the scrollview
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y += (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.1];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310,580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = NO;
}
- (void)keyboardWillShow:(NSNotification *)n
{
// This is an ivar I'm using to ensure that we do not do the frame size adjustment on the UIScrollView if the keyboard is already shown. This can happen if the user, after fixing editing a UITextField, scrolls the resized UIScrollView to another UITextField and attempts to edit the next UITextField. If we were to resize the UIScrollView again, it would be disastrous. NOTE: The keyboard notification will fire even when the keyboard is already shown.
if (keyboardIsShown) {
return;
}
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
// resize the noteView
CGRect viewFrame = self.NoteTextView.frame;
// I'm also subtracting a constant kTabBarHeight because my UIScrollView was offset by the UITabBar so really only the portion of the keyboard that is leftover pass the UITabBar is obscuring my UIScrollView.
viewFrame.origin.y -= (keyboardSize.height * 0.36);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
// The kKeyboardAnimationDuration I am using is 0.3
[UIView setAnimationDuration:0.3];
[self.NoteTextView setFrame:viewFrame];
[UIView commitAnimations];
[self.NoteTextView setContentSize:CGSizeMake(310, 580)];
[self.NoteTextView setScrollEnabled:YES];
keyboardIsShown = YES;
}
I have even enabled scrolling enabled and changed its content size in the methods.
It sound really weird.
My Suggestions:
1. Check that non of its superview's UserInteractioEnable property in the new frame isn't false
2. Try this code on new and clear project.
I currently have a UITextField on top of a keyboard. When you tap it, it should stick on top of the keyboard and move up smoothly. I don't know the exact duration and animation type of the keyboard, so it's really bumpy. Here's what I have:
[theTextView resignFirstResponder];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
// Frame changes go here (move down 216px)
[UIView commitAnimations];
[theTextView becomeFirstResponder];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.25];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
// Frame changes go here (move up 216px)
[UIView commitAnimations];
If anyone has done something like this before, I would like to know the settings you used to make the animation smooth and make it appear that the bar is "stuck" to the top of the keyboard.
UIKit posts UIKeyboardWillShowNotification when it shows the keyboard, and UIKeyboardWillHideNotification when it hides the keyboard. These notifications contain everything you need to properly animate your UITextField.
Let's say your UITextField is in a property called called myTextField.
First, you need to register for the notifications somewhere. Where you register depends on what object is responsible for moving myTextField. In my project, the field's superview is responsible, and since I load my UI from a nib, I do it in the superview's awakeFromNib:
- (void)awakeFromNib
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHideOrShow:) name:UIKeyboardWillShowNotification object:nil];
}
If you use a UIViewController to move the field around, you'll probably want to do it in viewWillAppear:animated:.
You should unregister in your dealloc or viewWillDisappear:animated::
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Of course the tricky bit is in the keyboardWillHideOrShow: method. First I extract the animation parameters from the notification:
- (void)keyboardWillHideOrShow:(NSNotification *)note
{
NSDictionary *userInfo = note.userInfo;
NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
The keyboardFrame is in the global coordinate system. I need to convert the frame to the same coordinate system as myTextField.frame, and myTextField.frame is in the coordinate system of myTextField.superview:
CGRect keyboardFrameForTextField = [self.myTextField.superview convertRect:keyboardFrame fromView:nil];
Next, I compute the frame that I want myTextField to move to. The bottom edge of the new frame should be equal to the top edge of the keyboard's frame:
CGRect newTextFieldFrame = self.myTextField.frame;
newTextFieldFrame.origin.y = keyboardFrameForTextField.origin.y - newTextFieldFrame.size.height;
Finally, I animate myTextField to its new frame, using the same animation parameters that the keyboard is using:
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
self.myTextField.frame = newTextFieldFrame;
} completion:nil];
}
Here it is all put together:
- (void)keyboardWillHideOrShow:(NSNotification *)note
{
NSDictionary *userInfo = note.userInfo;
NSTimeInterval duration = [[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
UIViewAnimationCurve curve = [[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
CGRect keyboardFrameForTextField = [self.myTextField.superview convertRect:keyboardFrame fromView:nil];
CGRect newTextFieldFrame = self.myTextField.frame;
newTextFieldFrame.origin.y = keyboardFrameForTextField.origin.y - newTextFieldFrame.size.height;
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionBeginFromCurrentState | curve animations:^{
self.myTextField.frame = newTextFieldFrame;
} completion:nil];
}
Set your text field (or a view holding the text field) as the inputAccessoryView of the field that you are editing. It will then automatically be attached to the top of the keyboard and animate appropriately.
in order to make the UITextField to dock to keyboard (with animation), you need to do offset calculations and apply offset changes on the scroll view (assuming UITextField is placed in UIScrollView) using setContentOffset:animation: method.
Use this code in your keyboard notification:
#objc func keyboardWillShowNotification(notification: Notification) {
let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height ?? 216
let duration = notification.userInfo?[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0.25
let curve = (notification.userInfo?[UIKeyboardAnimationCurveUserInfoKey] as? UInt ?? 7) << 16
tableViewBottomConstraint.constant = keyboardHeight - submitButtonContainer.frame.size.height
UIView.animate(withDuration: duration, delay: 0, options: [UIViewAnimationOptions(rawValue: curve)], animations: {
// Animation
}, completion: nil)
}
I have a search bar at the bottom of a view. The issue is whenever I type something in the keyboard, the search bar still remains at the bottom and I cannot view what I am typing. I would like to dynamically move it up whenever the keyboards pops up and then take back its original position after the keyboard disappears. And unfortunately the search bar has to be in the bottom for my app and kind of stuck in this.
Is there any way around to move the search bar up only when the keyboard appears? Any code snippets would be really helpful.
Your best bet is probably to use the –searchBarShouldBeginEditing: in the UISearchBarDelegate protocol.
It would look something like this :
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
CGRect newFrame = //some rect
mySearchBar.frame = newFrame;
return YES;//this is important!
}
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
CGRect originalFrame = //the original frame
mySearchBar.frame = originalFrame;
return YES;
}
EDIT: One of the other answers suggests using the UIKeyboard notifications, but that can be confusing. It does, however, give the advantage of working for every time the keyboard appears, rather than just when the UISearchBar is the first responder.
EDIT 2:
Mayur Joshi suggests using animation, which can be done like so:
[UIView animateWithDuration:duration
animations:^{
//what you want to animate (in this case, the search bar's frame)
}
completion:^(BOOL finished){
//what to do when the animation finishes
}];
EDIT 3:
If you don't want to obscure the view behind the search bar, you will have to shrink its height whenever the search bar moves up. It can go in the same place as the code to animate your search bar.
Hi, try this
sBar is UISearchBar object.
- (void)keyboardWillShow:(NSNotification *)aNotification
{
// the keyboard is showing so resize the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = sBar.frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
frame.origin.y=frame.origin.y- keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
sBar.frame = frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)aNotification
{
// the keyboard is hiding reset the table's height
CGRect keyboardRect = [[[aNotification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
NSTimeInterval animationDuration =
[[[aNotification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
CGRect frame = sBar.frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
frame.origin.y=frame.origin.y+ keyboardRect.size.height;
[UIView beginAnimations:#"ResizeForKeyboard" context:nil];
[UIView setAnimationDuration:animationDuration];
sBar.frame = frame;
NSLog(#"%f",frame.size.height);
NSLog(#"%f",frame.origin.y);
[UIView commitAnimations];
}
You will have to use a UIScrollView and keep this search bar in that scroll View. Now, when you start editing the Search Bar, that is,
- (void) searchBarTextDidBeginEditing:(UISearchBar *)theSearchBar
set the scrollRectToVisible method for the UIScrollView so as to make your SearchBar visible like this....
[yourScrollView scrollRectToVisible:CGRectMake(0, 300, yourScrollView.frame.size.width, yourScrollView.frame.size.height) animated:YES];
And when you have written the text in the search bar, i.e
- (void)searchBarTextDidEndEditing:(UISearchBar *)searchBar1
set the Scroll view scrollRectToVisible to its original size.
[yourScrollView scrollRectToVisible:CGRectMake(0, 0, yourScrollView.frame.size.width, yourScrollView.frame.size.height) animated:YES];
I use the following method to resize the view after keyboard show/hide:
- (void)moveViewForKeyboard:(NSNotification*)aNotification up:(BOOL)up {
NSDictionary* userInfo = [aNotification userInfo];
// Get animation info from userInfo
NSTimeInterval animationDuration;
UIViewAnimationCurve animationCurve;
CGRect keyboardEndFrame;
[[userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve];
[[userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration];
[[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
// Animate up or down
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationCurve:animationCurve];
CGRect newFrame = self.view.frame;
CGRect keyboardFrame = [self.view convertRect:keyboardEndFrame toView:nil];
newFrame.size.height += (up? -1 : 1) * keyboardFrame.size.height;
self.view.frame = newFrame;
keyboardUp = up;
[UIView commitAnimations];
}
This works very good, until the screen orientation changes. What happens then is that the method resizes the view correctly, but after this method returns - something else resizes the view again to the maximum height of the screen.
Any ideas?
First you'll need to figure out what is resizing the view again. I would recommend putting a breakpoint into the above method so when it gets called that 2nd, unwanted time, you can look at the method call stack and see what is causing the 2nd call. Then you'll be able to stop it from happening, or change your code so that it doesn't cause a problem.
I have a text view (nib-file) with a UITextView maximised the entire view.
When ever i push the viewcontroller on to the navigationcontroller i load the keyboard in the text view's viewDidLoad method.
My problem is that when i write text that has more lines than there is space for, the text is behind the keyboard. I followed the sampe from Apple here.
If i log the "newTextViewFrame" it's NULL. but if i debug the thing it has a fine value.
Even if i hardcode it, the UITextView doesent change size.
Here is my code:
- (void)keyboardWillShow:(NSNotification *)notification {
/*
Reduce the size of the text view so that it's not obscured by the keyboard.
Animate the resize so that it's in sync with the appearance of the keyboard.
*/
NSDictionary *userInfo = [notification userInfo];
// Get the origin of the keyboard when it's displayed.
NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey];
// Get the top of the keyboard as the y coordinate of its origin in self's view's coordinate system. The bottom of the text view's frame should align with the top of the keyboard's final position.
CGRect keyboardRect = [aValue CGRectValue];
keyboardRect = [self.view convertRect:keyboardRect fromView:nil];
CGFloat keyboardTop = keyboardRect.origin.y;
CGRect newTextViewFrame = self.view.bounds;
newTextViewFrame.size.height = keyboardTop; - (self.view.bounds.origin.y);
// Get the duration of the animation.
NSValue *animationDurationValue = [userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSTimeInterval animationDuration;
[animationDurationValue getValue:&animationDuration];
// Animate the resize of the text view's frame in sync with the keyboard's appearance.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:animationDuration];
createListingTextView.frame = newTextViewFrame;
[UIView commitAnimations];
NSLog(#"Textview resized: %#", newTextViewFrame);
}
My task i simple: Implement a View with a UITextView and the keyboard open and scroll the UITextView when ever the text exceeds.
Please advice...
There is a semi-colon after keyboardTop on the line
newTextViewFrame.size.height = keyboardTop; - (self.view.bounds.origin.y);
This would certainly prevent newTextViewFrame from getting the adjusted height.