In my app, when I click on a text field, the keyboard hides it. Please help me -- how can I move my view up when I click on the text field. I'm using this code in textFieldDidBeginEditing:
self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(0, 0, 216, 0);
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 216, 0);
but it doesn't work.
You should not trust textFieldDidBeginEditing: to adjust for the keyboard, since this method will be called even if the user is typing using a physical keyboard where an onscreen keyboard will not be displayed.
Instead listen to the UIKeyboardWillShowNotification, that is only triggered when the keyboard will actually be displayed. You need to do a three step process:
Determine actual size of keyboard from the notifications userInfo dictionary. The size will differ from landscape/portrait, and different devices.
Update the contentInset using the determined size. You can do it animated, the notification will even tell you the duration for the keyboard animation.
Scroll the textfield into view, very easy to forget this!
You find more information and sample code from here
You can do the following, but first make sure you've set the UITextField delegate to your self and
#define kOFFSET_FOR_KEYBOARD 350;
at the top. This is how far you want the view to be shifted
//method to move the view up/down whenever the keyboard is shown/dismissed
-(void)setViewMovedUp:(BOOL)movedUp
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // if you want to slide up the view
[UIView setAnimationBeginsFromCurrentState:YES];
CGRect rect = self.view.frame;
if (movedUp)
{
// 1. move the view's origin up so that the text field that will be hidden come above the keyboard
// 2. increase the size of the view so that the area behind the keyboard is covered up.
if (rect.origin.y == 0 ) {
rect.origin.y -= kOFFSET_FOR_KEYBOARD;
//rect.size.height += kOFFSET_FOR_KEYBOARD;
}
}
else
{
if (stayup == NO) {
rect.origin.y += kOFFSET_FOR_KEYBOARD;
//rect.size.height -= kOFFSET_FOR_KEYBOARD;
}
}
self.view.frame = rect;
[UIView commitAnimations];
}
- (void)keyboardWillHide:(NSNotification *)notif {
[self setViewMovedUp:NO];
}
- (void)keyboardWillShow:(NSNotification *)notif{
[self setViewMovedUp:YES];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
stayup = YES;
[self setViewMovedUp:YES];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
stayup = NO;
[self setViewMovedUp:NO];
}
- (void)viewWillAppear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification object:self.view.window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification object:self.view.window];
}
- (void)viewWillDisappear:(BOOL)animated
{
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
Related
I have a ScrollView in which there are TableViews. I set when the keyboard appears, the content above the keyboard should move, so the keyboard won't obscure anything. How can I scroll what is above the keyboard, only when the keyboard is up?
You can add add observer to check keyboard is showing or not.
NotificationCenter.default.addObserver(self,
selector: #selector(viewController.keyboardWillShow(notification:)),
name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(viewController.keyboardWillHide(notification:)),
name: NSNotification.Name.UIKeyboardWillHide, object: nil)
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo? [UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("Show")
}
}
func keyboardWillHide(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
print("Hide")
}
}
And then you need to do calculation for content to show when keyboard will appear and set content offset of scrollview.
You need to manage the height of UITableView when the keyboard is up and down. Notification will help to manage state of wheather keyboard is up or not. According to state, we can udpate UITableView's height.
-(void) keyboardWillShow:(NSNotification *)note{
// get keyboard size and loctaion
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds];
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
// Need to translate the bounds to account for rotation.
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
// animations settings
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
// set views with new info
_containerBottom.constant = keyboardBounds.size.height;
CGRect rectTable = _tblMessages.frame;
rectTable.size.height -= keyboardBounds.size.height;
_tblMessages.frame = rectTable;
[self.view layoutIfNeeded];
[self scrollToBottom];
// commit animations
[UIView commitAnimations];
}
-(void) keyboardWillHide:(NSNotification *)note{
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds];
keyboardBounds = [self.view convertRect:keyboardBounds toView:nil];
NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey];
NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey];
// animations settings
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:[duration doubleValue]];
[UIView setAnimationCurve:[curve intValue]];
CGRect rectTable = _tblMessages.frame;
rectTable.size.height += keyboardBounds.size.height;
_tblMessages.frame = rectTable;
// commit animations
[UIView commitAnimations];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
// unregister for keyboard notifications while not visible.
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
}
All is working good till iOS 8.
But when user tap on text field control comes directly in UIKeyboardWillHideNotification notification
Log in console -Can't find keyplane that supports type 4 for keyboard iPhone-PortraitTruffle-NumberPad; using 675849259_PortraitTruffle_iPhone-Simple-Pad_Default
Here is the code--
`
In view did load
- (void)viewDidLoad {
[super viewDidLoad];
self.txtMobNumber.delegate = self;
self.txtMobNumber.keyboardType = UIKeyboardTypeNumberPad;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:#"UIKeyboardWillShowNotification" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:#"UIKeyboardWillHideNotification" object:nil];
}
notification callback
- (void)keyboardWillShow:(NSNotification *)notification
{
// Save the height of keyboard and animation duration
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardRect = [userInfo[#"UIKeyboardBoundsUserInfoKey"] CGRectValue];
[UIView beginAnimations:#"moveKeyboard" context:nil];
float height = keyboardRect.size.height-60;
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - height, self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
// [self setNeedsUpdateConstraints];
}
// Reset the desired height
- (void)keyboardWillHide:(NSNotification *)notification
{
// Reset the desired height (keep the duration)
NSDictionary *userInfo = [notification userInfo];
CGRect keyboardRect = [userInfo[#"UIKeyboardBoundsUserInfoKey"] CGRectValue];
[UIView beginAnimations:#"moveKeyboard" context:nil];
float height = keyboardRect.size.height-60;
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y + height, self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
`
This can be related to simulator setup, see menu "Hardware > Keyboard > Connect Keyboard Hardware". If this option is ON, you will get UIKeyboardWillHideNotification, but never UIKeyboardWillShowNotification.
I have a form which has multiple textfields and textviews. When keyboad is shown I update scrollview frame to prevent textfields hiding under keyboard.
I did follow this question and implement a similar solution.
It works with uitextfields actually but not for uitextviews.
When keyboard is shown scrollview height's is reduced as much as keyboard height and then scroll to focused uitextfield. But if the focused item is uitextview it just doesnt scroll while height of uiscrollview is reduced.
IB screenshots for my scrollview;
https://www.dropbox.com/s/a1iblh6nsdqy34t/Screenshot%202014-05-30%2021.44.32.png
https://www.dropbox.com/s/o2h8avt5w82r5eo/Screenshot%202014-05-30%2021.45.19.png
Here is the code;
// register for keyboard notifications
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidShow:)
name:UIKeyboardDidShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardDidHide:)
name:UIKeyboardDidHideNotification
object:nil];
Notification handler;
-(void)keyboardWillShow:(NSNotification *)n {
if(keyboardUp)
return;
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
const int movementDistance = -keyboardSize.height - keyboardPaddingToScrollView;
const float movementDuration = 0.30f;
int movement = movementDistance;
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
CGRect contentSize = self.view.frame;
contentSize.size.height += movementDistance;
[self.view setFrame:contentSize];
[UIView commitAnimations];
}
-(void)keyboardDidShow:(NSNotification *)n {
keyboardUp = true;
NSLog(NSStringFromCGRect(self.view.frame));
}
-(void)keyboardWillHide:(NSNotification *)n {
if(!keyboardUp)
return;
NSDictionary* userInfo = [n userInfo];
// get the size of the keyboard
CGSize keyboardSize = [[userInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
const int movementDistance = keyboardSize.height + keyboardPaddingToScrollView;
const float movementDuration = 0.30f;
int movement = movementDistance;
[UIView beginAnimations: #"anim" context: nil];
[UIView setAnimationBeginsFromCurrentState: YES];
[UIView setAnimationDuration: movementDuration];
CGRect contentSize = self.view.frame;
contentSize.size.height += movementDistance;
self.view.frame = contentSize;
[UIView commitAnimations];
}
-(void)keyboardDidHide:(NSNotification *)n {
keyboardUp = false;
}
I have a UIScrollView which has several dynamic views inside of it, each of which has a text field. When I begin typing in one of the boxes, I want the scroll view to scroll so that the field is at the top of the screen (visible above the keyboard). It works great; here is the code:
(void)didStartTyping:(id)sender {
[scrollView setContentOffset:CGPointMake(0, subView.frame.origin.y) animated:YES];
scrollView.scrollEnabled = NO;
}
(void)didFinishTyping:(id)sender {
scrollView.scrollEnabled = YES;
}
But, whenever the scroll view is scrolled up to the very top and I begin typing in the lowest visible text field, it doesn't scroll down far enough (short by about 40 px). The puzzling thing is that it works if I scroll down just one pixel from the top of the scroll view, but when I scroll up to the top it behaves very differently.
The best way i have managed to do this is to grab the keyboard frame, then update my scrollview insets when a text view gets textViewDidBeginEditing: called. Here im using a tableview, but the same logic should apply to a scrollview, the main difference being how you scroll. I use scrollToRowAtIndexPath, you will want to use scrollRectToVisible
//setup keyboard callbacks
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillHideNotification
object:nil];
}
- (void)keyboardWillShow:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
kbFrame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
}
//this is called from your UITextViewDelegate when textViewDidBeginEditing: is called
- (void)updateActiveTextScroll:(UITextView*)textView
{
activeTextView = textView;
UIEdgeInsets inset;
UIInterfaceOrientation orient = [[UIApplication sharedApplication] statusBarOrientation];
if( UIInterfaceOrientationIsLandscape(orient) )
{
inset = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.width, 0.0);
}
else
{
inset = UIEdgeInsetsMake(0.0, 0.0, kbFrame.size.height, 0.0);
}
myTableView.contentInset = inset;
myTableView.scrollIndicatorInsets = inset;
[myTableView scrollToRowAtIndexPath:activeNSIndexPath
atScrollPosition:UITableViewScrollPositionBottom
animated:YES];
}
//dont forget to reset when the keyboard goes away
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets inset = UIEdgeInsetsZero;
myTableView.contentInset = inset;
myTableView.scrollIndicatorInsets = inset;
}
I tried this but view is too little to scroll up. How can I scroll more ?
// Call this method somewhere in your view controller setup code.
- (void)registerForKeyboardNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWasShown:)
name:UIKeyboardDidShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillBeHidden:)
name:UIKeyboardWillHideNotification object:nil];
}
// Called when the UIKeyboardDidShowNotification is sent.
- (void)keyboardWasShown:(NSNotification*)aNotification
{
NSDictionary* info = [aNotification userInfo];
CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, kbSize.height, 0.0);
scroll.contentInset = contentInsets;
scroll.scrollIndicatorInsets = contentInsets;
// If active text field is hidden by keyboard, scroll it so it's visible
// Your application might not need or want this behavior.
CGRect aRect = self.view.frame;
aRect.size.height -= kbSize.height;
if (!CGRectContainsPoint(aRect, EPostaText.frame.origin) ) {
CGPoint scrollPoint = CGPointMake(0.0, EPostaText.frame.origin.y-(aRect.size.height));
[scroll setContentOffset:scrollPoint animated:YES];
}
}
// Called when the UIKeyboardWillHideNotification is sent
- (void)keyboardWillBeHidden:(NSNotification*)aNotification
{
UIEdgeInsets contentInsets = UIEdgeInsetsZero;
scroll.contentInset = contentInsets;
scroll.scrollIndicatorInsets = contentInsets;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
EPostaText = textField;
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
EPostaText = nil;
}
The best approach - it is resize the scroll view container to visible area and use this:
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated
Since I found it, I use TPKeyboardAvoiding
It is working great, and is very easy to setup:
Add a UIScrollView into your view controller's xib
Set the scroll view's class to TPKeyboardAvoidingScrollView (still
in the xib, via the identity inspector)
Place all your controls within that scrollview
Good luck!
This is my code, hope it will help you. It work ok in case you have many textfield
CGPoint contentOffset;
bool isScroll;
- (void)textFieldDidBeginEditing:(UITextField *)textField {
contentOffset = self.myScroll.contentOffset;
CGPoint newOffset;
newOffset.x = contentOffset.x;
newOffset.y = contentOffset.y;
//check push return in keyboar
if(!isScroll){
//180 is height of keyboar
newOffset.y += 180;
isScroll=YES;
}
[self.myScroll setContentOffset:newOffset animated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
//reset offset of content
isScroll = NO;
[self.myScroll setContentOffset:contentOffset animated:YES];
[textField endEditing:true];
return true;
}