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
}
Keyboard covers text fields at the bottom of my view
This code will work, making your textField animating to above keyboard if its frame intersects with that of keyboard and animating back to original position on keyboard hide.
@IBOutlet weak var textField: UITextField!
var offsetY:CGFloat = 0
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardFrameChangeNotification(notification:)), name: NSNotification.Name.UIKeyboardWillChangeFrame, object: nil)
}
func keyboardFrameChangeNotification(notification: Notification) {
if let userInfo = notification.userInfo {
let endFrame = userInfo[UIKeyboardFrameEndUserInfoKey] as? CGRect
let animationDuration = userInfo[UIKeyboardAnimationDurationUserInfoKey] as? Double ?? 0
let animationCurveRawValue = (userInfo[UIKeyboardAnimationCurveUserInfoKey] as? Int) ?? Int(UIViewAnimationOptions.curveEaseInOut.rawValue)
let animationCurve = UIViewAnimationOptions(rawValue: UInt(animationCurveRawValue))
if let _ = endFrame, endFrame!.intersects(self.textField.frame) {
self.offsetY = self.textField.frame.maxY - endFrame!.minY
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.textField.frame.origin.y = self.textField.frame.origin.y - self.offsetY
}, completion: nil)
} else {
if self.offsetY != 0 {
UIView.animate(withDuration: animationDuration, delay: TimeInterval(0), options: animationCurve, animations: {
self.textField.frame.origin.y = self.textField.frame.origin.y + self.offsetY
self.offsetY = 0
}, completion: nil)
}
}
}
}
How to move a UITextView when the keyboard covers it
The actual solution turned out to be very simple.
On the UITextView, set scrollingEnabled to False.
Thanks for all the assistance.
Move textfield up when keyboard covers it up
https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
Look at "Receiving keyboard notifications".
The code samples in that document are all Obj-C so you'll have to convert it to swift on your own, but as @jtbandes said, it's not a swift question per se.
Move view with keyboard using Swift
Here is a solution, without handling the switch from one textField to another:
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name: UIKeyboardWillHideNotification, object: nil)
}
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
self.view.frame.origin.y -= keyboardSize.height
}
}
func keyboardWillHide(notification: NSNotification) {
self.view.frame.origin.y = 0
}
To solve this, replace the two functions keyboardWillShow/Hide
with these:
func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.CGRectValue() {
if view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
func keyboardWillHide(notification: NSNotification) {
if view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
Swift 3.0:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
Swift 4.0:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillShow), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.keyboardWillHide), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
Swift 4.2:
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if self.view.frame.origin.y == 0 {
self.view.frame.origin.y -= keyboardSize.height
}
}
}
@objc func keyboardWillHide(notification: NSNotification) {
if self.view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
}
}
Keyboard covers UITextView
For UITextView it doesn't work, so i do this with contentOffset.
Swift 5
extension SummaryViewController {
private func registerKeyboardNotifications() {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIControl.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIControl.keyboardWillHideNotification, object: nil)
}
@objc func keyboardWillShow(_ notification: Notification) {
guard let keyboardFrameValue = notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue else { return }
let keyboardFrame = view.convert(keyboardFrameValue.cgRectValue, from: nil)
scrollView.contentOffset = CGPoint(x: 0, y: keyboardFrame.size.height)
}
@objc func keyboardWillHide(_ notification: Notification) {
scrollView.contentOffset = .zero
}
}
Related Topics
Nsinternalinconsistencyexception', Reason: 'Could Not Load Nib in Bundle: 'Nsbundle
How to Exclude Notes and Reminders Apps from the Uiactivityviewcontroller
Enumerate All Keychain Items in My iOS Application
How to Use an .A Static Library in Swift
How to Catch "Index Out of Range" in Swift
Cordova App Hanging During Startup on iOS 10
Ios App With Arc, Find Who Is Owner of an Object
Get the Current Scroll Position of a Swiftui Scrollview
Iphone Get a List of All Ssids Without Private Library
Cgcontextdrawimage Draws Image Upside Down When Passed Uiimage.Cgimage
How to Make Uilabel Display Outlined Text
Ios: Multi-Line Uilabel in Auto Layout
Uiviewcontroller Viewdidload Vs. Viewwillappear: What Is the Proper Division of Labor
How to Create a Swift Date Object
How to Locate the Cgrect For a Substring of Text in a Uilabel