Move UIView up when keyboard appears in iOS

I have a UIView, it is not inside a UIScrollView. I would like to move my view when the keyboard appears. Before I tried to use this solution: How can I make UITextField move up with a keyboard? ,

It worked fine. But after inserting the data into the text fields, I switch to another view, and when I return to this page, they just jump and I do not see my text fields. Is there a better solution to this problem?

+68
ios objective-c xcode uiviewcontroller uiview
Jul 01 2018-12-12T00:
source share
19 answers

Use the following code to show and hide the keyboard

//Declare a delegate, assign your textField to the delegate and then include these methods -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil]; return YES; } - (BOOL)textFieldShouldEndEditing:(UITextField *)textField { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil]; [self.view endEditing:YES]; return YES; } - (void)keyboardDidShow:(NSNotification *)notification { // Assign new frame to your view [self.view setFrame:CGRectMake(0,-110,320,460)]; //here taken -110 for example ie your view will be scrolled to -110. change its value according to your requirement. } -(void)keyboardDidHide:(NSNotification *)notification { [self.view setFrame:CGRectMake(0,0,320,460)]; } 
+78
Jul 01 2018-12-12T00:
source share
 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; [[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]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - keyboard movements - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = -keyboardSize.height; self.view.frame = f; }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = 0.0f; self.view.frame = f; }]; } 
+83
Jan 21 '14 at 11:37
source share

I wrote a small category on UIView that controls the time scrolling without having to wrap it all in a UIScrollView . My use of the scrolling verb here may not be ideal, because it may make you think that the scroll view is used here, but not there - we just UIView position of the UIView (or subclass of UIView ).

There are some magic numbers that match my shape and layout, which may not match yours, so I recommend tweaking this to suit your specific needs.

UIView + FormScroll.h:

 #import <Foundation/Foundation.h> @interface UIView (FormScroll) -(void)scrollToY:(float)y; -(void)scrollToView:(UIView *)view; -(void)scrollElement:(UIView *)view toPoint:(float)y; @end 

UIView + FormScroll.m:

 #import "UIView+FormScroll.h" @implementation UIView (FormScroll) -(void)scrollToY:(float)y { [UIView beginAnimations:@"registerScroll" context:NULL]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.4]; self.transform = CGAffineTransformMakeTranslation(0, y); [UIView commitAnimations]; } -(void)scrollToView:(UIView *)view { CGRect theFrame = view.frame; float y = theFrame.origin.y - 15; y -= (y/1.7); [self scrollToY:-y]; } -(void)scrollElement:(UIView *)view toPoint:(float)y { CGRect theFrame = view.frame; float orig_y = theFrame.origin.y; float diff = y - orig_y; if (diff < 0) { [self scrollToY:diff]; } else { [self scrollToY:0]; } } @end 

Import this into your UIViewController and then you can do

 - (void)textFieldDidBeginEditing:(UITextField *)textField { [self.view scrollToView:textField]; } -(void) textFieldDidEndEditing:(UITextField *)textField { [self.view scrollToY:0]; [textField resignFirstResponder]; } 

... or whatever. This category gives you three very good ways to adjust the position of the view.

+37
Jul 01 2018-12-12T00:
source share

Snap a view to the keyboard is also an option (see GIF at the bottom of the answer)

Swift 4

Use extension: (has not been fully tested)

 extension UIView{ func bindToKeyboard(){ NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(notification:)), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil) } func unbindToKeyboard(){ NotificationCenter.default.removeObserver(self, name: Notification.Name.UIKeyboardWillChangeFrame, object: nil) } @objc func keyboardWillChange(notification: Notification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y+=deltaY },completion: nil) } } 

Swift 2 + 3

Use the extension:

 extension UIView{ func bindToKeyboard(){ NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: UIKeyboardWillChangeFrameNotification, object: nil) } func keyboardWillChange(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).CGRectValue() let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).CGRectValue() let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframesWithDuration(duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y+=deltaY },completion: nil) } } 

Using:

 // view did load... textField.bindToKeyboard() 

...

 // view unload textField.unbindToKeyboard() 

result:
enter image description here

important
Do not forget to remove the observer when unloading the view

+30
May 03 '16 at 11:57
source share

I found theDuncs answer very useful, and below you can find my own (reworked) version:




Major changes

  1. Now we get the dynamic size of the keyboard , rather than hard encoding values
  2. Extracts UIView Animation from a native method to avoid code duplication
  3. Valid duration to be passed to the method, not hardcoded



 - (void)viewWillAppear:(BOOL)animated { [[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 { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } 



 - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size; float newVerticalPosition = -keyboardSize.height; [self moveFrameToVerticalPosition:newVerticalPosition forDuration:0.3f]; } - (void)keyboardWillHide:(NSNotification *)notification { [self moveFrameToVerticalPosition:0.0f forDuration:0.3f]; } - (void)moveFrameToVerticalPosition:(float)position forDuration:(float)duration { CGRect frame = self.view.frame; frame.origin.y = position; [UIView animateWithDuration:duration animations:^{ self.view.frame = frame; }]; } 
+11
Feb 26 '15 at 21:19
source share

Based on the decision of Daniel Crom. This is the version in swift 3.0 . Works great with AutoLayout and moves the whole view when the keyboard appears.

 extension UIView { func bindToKeyboard(){ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) } func unbindFromKeyboard(){ NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil) } @objc func keyboardWillChange(notification: NSNotification) { guard let userInfo = notification.userInfo else { return } let duration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = userInfo[UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y += deltaY }) } } 

How to use it: Add the bindToKeyboard function to viewDidLoad , for example:

 override func viewDidLoad() { super.viewDidLoad() view.bindToKeyboard() } 

And add the unbindFromKeyboard function to deinit:

 deinit { view.unbindFromKeyboard() } 
+9
Mar 06 '17 at 21:20
source share

For all questions related to KeyBoard, just use IQKeyBoardManager, this is useful. https://github.com/hackiftekhar/IQKeyboardManager .

+5
Apr 7 '15 at 13:15
source share

try the following: -

  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector (keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil]; -(void) keyboardDidShow: (NSNotification *)notif { CGSize keyboardSize = [[[notif userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; UIEdgeInsets contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height+[self getTableView].tableFooterView.frame.size.height, 0.0); [self getTableView].contentInset = contentInsets; [self getTableView].scrollIndicatorInsets = contentInsets; CGRect rect = self.frame; rect.size.height -= keyboardSize.height; if (!CGRectContainsPoint(rect, self.frame.origin)) { CGPoint scrollPoint = CGPointMake(0.0, self.frame.origin.y - (keyboardSize.height - self.frame.size.height)); [[self getTableView] setContentOffset:scrollPoint animated:YES]; } } -(void) keyboardDidHide: (NSNotification *)notif { UIEdgeInsets contentInsets = UIEdgeInsetsZero; [self getTableView].contentInset = contentInsets; [self getTableView].scrollIndicatorInsets = contentInsets; } 
+5
Apr 16 '15 at 9:07
source share

Based on a Dunc answer , but written in Swift with auto-detection.

 @IBOutlet weak var bottomConstraint: NSLayoutConstraint! // connect the bottom of the view you want to move to the bottom layout guide override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ConversationViewController.keyboardWillShow(_:)), name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ConversationViewController.keyboardWillHide(_:)), name: UIKeyboardWillHideNotification, object: nil) } override func viewWillDisappear(animated: Bool) { NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil) super.viewWillDisappear(animated) } // MARK: - Keyboard events func keyboardWillShow(notification: NSNotification) { if let userInfo = notification.userInfo, keyboardFrame = userInfo[UIKeyboardFrameBeginUserInfoKey] { let keyboardSize = keyboardFrame.CGRectValue().size self.bottomConstraint.constant = keyboardSize.height UIView.animateWithDuration(0.3) { self.view.layoutIfNeeded() } } } func keyboardWillHide(notification: NSNotification) { self.bottomConstraint.constant = 0 UIView.animateWithDuration(0.3) { self.view.layoutIfNeeded() } } 
+3
Aug 17 '16 at 5:20
source share

I have implemented a custom controller that dynamically calculates the size of the keyboard by scrolling through textFields when it appears and disappears even while the device is spinning. Works with all iOS devices. Just inherit the controller to have what you need. You can find it with all the instructions at the following link: https://github.com/mikthebig/ios-textfield-scroll

+2
Apr 03 '13 at 2:07 on
source share

A simple solution without adding observer notification

 -(void)setViewMovedUp:(BOOL)movedUp { [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration:0.3]; // if you want to slide up the view CGRect rect = self.view.frame; if (movedUp) { // 1. move the view 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. rect.origin.y -= kOFFSET_FOR_KEYBOARD; rect.size.height += kOFFSET_FOR_KEYBOARD; } else { // revert back to the normal state. rect.origin.y += kOFFSET_FOR_KEYBOARD; rect.size.height -= kOFFSET_FOR_KEYBOARD; } self.view.frame = rect; [UIView commitAnimations]; } -(void)textFieldDidEndEditing:(UITextField *)sender { if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:NO]; } } -(void)textFieldDidBeginEditing:(UITextField *)sender { //move the main view, so that the keyboard does not hide it. if (self.view.frame.origin.y >= 0) { [self setViewMovedUp:YES]; } } 

Where

 #define kOFFSET_FOR_KEYBOARD 80.0 
+2
Oct. 25 '14 at 10:53
source share

Here you go. I used this code with a UIView, though. You should be able to make these settings for scrollview.

  func addKeyboardNotifications() { NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) } func keyboardWillShow(notification: NSNotification) { if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double // if using constraints // bottomViewBottomSpaceConstraint.constant = keyboardSize.height self.view.frame.origin.y -= keyboardSize.height UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() } } } func keyboardWillHide(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double //if using constraint // bottomViewBottomSpaceConstraint.constant = 0 self.view.frame.origin.y = 0 UIView.animate(withDuration: duration) { self.view.layoutIfNeeded() } } 

Remember to delete the notifications in the right place.

 func removeKeyboardNotifications() { NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIKeyboardWillHide, object: nil) } 
+1
Jul 28 '17 at 20:50
source share

Swift 4

 NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillChange), name: .UIKeyboardWillChangeFrame, object: nil) @objc func keyboardWillChange(notification: NSNotification) { let duration = notification.userInfo![UIKeyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIKeyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIViewKeyframeAnimationOptions(rawValue: curve), animations: { self.YourView.frame.origin.y+=deltaY },completion: nil) } 
+1
Jan 25 '18 at 20:07
source share

Just in case, if someone is looking for a solution in Swift , add this to your code:

 override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: .UIKeyboardWillHide, object: nil) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillShow, object: nil) NotificationCenter.default.removeObserver(self, name: .UIKeyboardWillHide, object: nil) } @objc func keyboardWillShow(notification: Notification) { if let userInfo = notification.userInfo { if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue { UIView.animate(withDuration: 0.3) { var alteredFrame = self.view.frame alteredFrame.origin.y = -keyboardSize.height self.view.frame = alteredFrame } } } } @objc func keyboardWillHide(notification: Notification) { UIView.animate(withDuration: 0.3) { var alteredFrame = self.view.frame alteredFrame.origin.y = 0.0 self.view.frame = alteredFrame } } 
+1
Mar 12 '18 at 16:31
source share

This can be done easily and automatically if this textfield is in the table cell (even when table.scrollable = NO ).

Please note : the position and size of the table should be reasonable. eg:

  • if the y position of table 100 is counted from the bottom of the view, then a keyboard 300 in height will cover the entire table.
  • if height = 10 table height = 10 , and the textfield in it must be scrolled to 100, when the keyboard appears to be visible, then this text field will be outside the table border.
0
Jan 08 '16 at 6:56
source share

Declare a delegate, assign a text box to the delegate, and then enable these methods.

Assuming you have a login form with text fields for email and password, this code is perfect:

 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self.emailTextField resignFirstResponder]; [self.passwordTextField resignFirstResponder]; } - (BOOL)textFieldShouldReturn:(UITextField *)textField { if (self.emailTextField == textField) { [self.passwordTextField becomeFirstResponder]; } else { [self.emailTextField resignFirstResponder]; [self.passwordTextField resignFirstResponder]; } return NO; } - (void)viewWillAppear:(BOOL)animated { [[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 { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; } #pragma mark - keyboard movements - (void)keyboardWillShow:(NSNotification *)notification { CGSize keyboardSize = [[[notification userInfo] objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = -0.5f * keyboardSize.height; self.view.frame = f; }]; } -(void)keyboardWillHide:(NSNotification *)notification { [UIView animateWithDuration:0.3 animations:^{ CGRect f = self.view.frame; f.origin.y = 0.0f; self.view.frame = f; }]; } 
0
Apr 20 '16 at 16:23
source share

I just created an easy keyboard manipulator to keep track of the keyboard frame.

Using:

  self.keyboardHandler = [EDKeyboardHandler new]; [self.keyboardHandler listenWithBlock:^(KeyboardInfo *model) { //adjust view positions according to keyboard position here }]; 

and the KeyboardInfo model has the following properties:

 typedef enum : NSUInteger { KeyboardStatusDidShow, KeyboardStatusWillShow, KeyboardStatusDidHide, KeyboardStatusWillHide, } KeyboardStatus; @interface KeyboardInfo:NSObject @property (nonatomic,readonly) NSTimeInterval animationDuration; @property (nonatomic,readonly) CGRect keyboardFrame; @property (nonatomic,readonly) NSInteger animationCurve; @property (nonatomic,readonly) KeyboardStatus status; @end 

check out the github project for details and cocoaPods integration.

0
Apr 28 '16 at 17:22
source share

Swift 5

Updated version of Daniel Krom's answer above:

 extension UIView { func bindToKeyboard() { NotificationCenter.default.addObserver( self, selector: #selector(UIView.keyboardWillChange(notification:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil ) } func unbindToKeyboard() { NotificationCenter.default.removeObserver( self, name: UIResponder.keyboardWillChangeFrameNotification, object: nil ) } @objc func keyboardWillChange(notification: Notification) { let duration = notification.userInfo![UIResponder.keyboardAnimationDurationUserInfoKey] as! Double let curve = notification.userInfo![UIResponder.keyboardAnimationCurveUserInfoKey] as! UInt let curFrame = (notification.userInfo![UIResponder.keyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue let targetFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue let deltaY = targetFrame.origin.y - curFrame.origin.y UIView.animateKeyframes(withDuration: duration, delay: 0.0, options: UIView.KeyframeAnimationOptions(rawValue: curve), animations: { self.frame.origin.y += deltaY }) } } 
0
Jun 20 '19 at 16:52
source share

based on textual guidance.

sample project

-3
Jan 25 '16 at 5:13
source share



All Articles