Move a view up only when the keyboard covers an input field
Your problem is well explained in this document by Apple. Example code on this page (at Listing 4-1
) does exactly what you need, it will scroll your view only when the current editing should be under the keyboard. You only need to put your needed controls in a scrollViiew.The only problem is that this is Objective-C and I think you need it in Swift..so..here it is:
Declare a variable
var activeField: UITextField?
then add these methods
func registerForKeyboardNotifications(){ //Adding notifies on keyboard appearing NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)}func deregisterFromKeyboardNotifications(){ //Removing notifies on keyboard appearing NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil) NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)}func keyboardWasShown(notification: NSNotification){ //Need to calculate keyboard exact size due to Apple suggestions self.scrollView.scrollEnabled = true var info : NSDictionary = notification.userInfo! var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeFieldPresent = activeField { if (!CGRectContainsPoint(aRect, activeField!.frame.origin)) { self.scrollView.scrollRectToVisible(activeField!.frame, animated: true) } }}func keyboardWillBeHidden(notification: NSNotification){ //Once keyboard disappears, restore original positions var info : NSDictionary = notification.userInfo! var keyboardSize = (info[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue().size var contentInsets : UIEdgeInsets = UIEdgeInsetsMake(0.0, 0.0, -keyboardSize!.height, 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets self.view.endEditing(true) self.scrollView.scrollEnabled = false}func textFieldDidBeginEditing(textField: UITextField!){ activeField = textField}func textFieldDidEndEditing(textField: UITextField!){ activeField = nil}
Be sure to declare your ViewController as UITextFieldDelegate
and set correct delegates in your initialization methods:ex:
self.you_text_field.delegate = self
And remember to call registerForKeyboardNotifications
on viewInit and deregisterFromKeyboardNotifications
on exit.
Edit/Update: Swift 4.2 Syntax
func registerForKeyboardNotifications(){ //Adding notifies on keyboard appearing NotificationCenter.default.addObserver(self, selector: #selector(keyboardWasShown(notification:)), name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillBeHidden(notification:)), name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)}func deregisterFromKeyboardNotifications(){ //Removing notifies on keyboard appearing NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIResponder.keyboardWillHideNotification, object: nil)}@objc func keyboardWasShown(notification: NSNotification){ //Need to calculate keyboard exact size due to Apple suggestions self.scrollView.isScrollEnabled = true var info = notification.userInfo! let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height, right: 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets var aRect : CGRect = self.view.frame aRect.size.height -= keyboardSize!.height if let activeField = self.activeField { if (!aRect.contains(activeField.frame.origin)){ self.scrollView.scrollRectToVisible(activeField.frame, animated: true) } }}@objc func keyboardWillBeHidden(notification: NSNotification){ //Once keyboard disappears, restore original positions var info = notification.userInfo! let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: -keyboardSize!.height, right: 0.0) self.scrollView.contentInset = contentInsets self.scrollView.scrollIndicatorInsets = contentInsets self.view.endEditing(true) self.scrollView.isScrollEnabled = false}func textFieldDidBeginEditing(_ textField: UITextField){ activeField = textField}func textFieldDidEndEditing(_ textField: UITextField){ activeField = nil}
Here is My 2 cents:
Have you tried: https://github.com/hackiftekhar/IQKeyboardManager
Extremely easy to install Swift or Objective-C.
Here how it works:
IQKeyboardManager (Swift):- IQKeyboardManagerSwift is available through CocoaPods, to install it simply add the following line to your Podfile: (#236)
pod 'IQKeyboardManagerSwift'
In AppDelegate.swift, just import IQKeyboardManagerSwift framework and enable IQKeyboardManager.
import IQKeyboardManagerSwift@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { IQKeyboardManager.sharedManager().enable = true // For Swift 4, use this instead // IQKeyboardManager.shared.enable = true return true }}
And that is all. Easy!
The one I found to work perfectly for me was this:
func textFieldDidBeginEditing(textField: UITextField) { if textField == email || textField == password { animateViewMoving(true, moveValue: 100) }}func textFieldDidEndEditing(textField: UITextField) { if textField == email || textField == password { animateViewMoving(false, moveValue: 100) }}func animateViewMoving (up:Bool, moveValue :CGFloat){ let movementDuration:NSTimeInterval = 0.3 let movement:CGFloat = ( up ? -moveValue : moveValue) UIView.beginAnimations("animateView", context: nil) UIView.setAnimationBeginsFromCurrentState(true) UIView.setAnimationDuration(movementDuration) self.view.frame = CGRectOffset(self.view.frame, 0, movement) UIView.commitAnimations()}
You can also change the height values. Remove the "if statement" if you want to use it for all text fields.
You can even use this for all controls that require user input like TextView.