Keyboard covers text fields at the bottom of my view
Solution 1
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)
}
}
}
}
Solution 2
You can use IQKeyboardManagerSwift to solve your issue easily and fast.
Use below pod in your pod file Which give support to Swift 4.
pod 'IQKeyboardManagerSwift', '5.0.0'
Here is link to implement IQKeyboardManagerSwift.
https://github.com/hackiftekhar/IQKeyboardManager
Thanks!!!
Solution 3
This piece of code worked for me.
In case of multiple textfields
I have implemented only for the textfields which are at the bottom (without using notification observer).
If you are using scrollView, this code might be helpful (scrollViewDidScroll is optional)
func scrollViewDidScroll(_ scrollView: UIScrollView) {
scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width, height: (scrollView.frame.size.height + 300))// To be more specific, I have used multiple textfields so wanted to scroll to the end.So have given the constant 300.
}
func textFieldDidBeginEditing(_ textField:UITextField) {
self.scrollView.setContentOffset(textField.frame.origin, animated: true)
}
and if you want to set the textfields position according to the view, try this:
func textFieldDidBeginEditing(_ textField:UITextField){
textField.frame.origin.y = textField.frame.origin.y - 150 //(If have not used contentsizing the scroll view then exclude this line)default origin takes the texfield to the top of the view.So to set lower textfields to proper position have used the constant 150.
self.scrollView.setContentOffset(textField.frame.origin, animated: true)
}
To do specifically for textfields at the bottom. Check their tag value textfield.tag in textFieldDidBeginEditing
func textFieldDidBeginEditing(_ textField:UITextField){
if textField.tag = 4 { //tag value of the textfield which are at the bottom
self.scrollView.setContentOffset(textField.frame.origin, animated: true)
}
}
If you implemented textfields in tableView go with notification observer which is explained below.
If there are multiple textfields in a tableView preferably go with Notification Observer
override func viewDidAppear(_ animated: Bool) {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: NSNotification.Name.UIKeyboardDidShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: NSNotification.Name.UIKeyboardDidHide, object: nil)
}
@objc func keyboardWillShow(notification: NSNotification) {
if let keyboardHeight = (notification.userInfo?[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height {
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardHeight, 0)
}
}
@objc func keyboardWillHide(notification: NSNotification) {
UIView.animate(withDuration: 0.2, animations: {
// For some reason adding inset in keyboardWillShow is animated by itself but removing is not, that's why we have to use animateWithDuration here
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
})
}
deinit {
print("denit")
NotificationCenter.default.removeObserver(self)
}
Solution 4
worked perfectly for me: http://www.seemuapps.com/move-uitextfield-when-keyboard-is-presented
If delegates are set right,
func textFieldDidBeginEditing(_ textField: UITextField) {
moveTextField(textField, moveDistance: -250, up: true)
}
// Finish Editing The Text Field
func textFieldDidEndEditing(_ textField: UITextField) {
moveTextField(textField, moveDistance: -250, up: false)
}
// Hide the keyboard when the return key pressed
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
// Move the text field in a pretty animation!
func moveTextField(_ textField: UITextField, moveDistance: Int, up: Bool) {
let moveDuration = 0.3
let movement: CGFloat = CGFloat(up ? moveDistance : -moveDistance)
UIView.beginAnimations("animateTextField", context: nil)
UIView.setAnimationBeginsFromCurrentState(true)
UIView.setAnimationDuration(moveDuration)
self.view.frame = self.view.frame.offsetBy(dx: 0, dy: movement)
UIView.commitAnimations()
}
Solution 5
Add an extensio to Uiview:
import UIKit
//Binding view to keyboard changes extension UIView {
func bindToKeyboard(){
NotificationCenter.default.addObserver(self, selector: #selector(UIView.keyboardWillChange(_:)), name: NSNotification.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.frame.origin.y += deltaY
},completion: {(true) in
self.layoutIfNeeded()
})
}
}
flaaghara
Updated on June 04, 2022Comments
-
flaaghara almost 2 years
I have searched
here: Move a view up only when the keyboard covers an input field
here: Move textfield when keyboard appears swift
here: How to make a UITextField move up when keyboard is present?
Unfortunately, all of the links and seemingly everywhere else I can find do not give a good clean solution that I am looking for. They are either outdated with Obj-c code, or plain do not work in the current iteration of Xcode 9 with Swift 4.
How do I manage a keyboard that is covering text fields at the bottom of my view? I want the screen's view to move only when they keyboard is covering the text field view, without using a scroll view, with the ability to animate this to make it look pretty rather than have it just snap, and most importantly I do not want to use an outside library.
CoreAnimation libraries from Apple are great and all, but all of the sample code is outdated and in objective c which is deprecated at this point (I cannot believe that Apple isn't updating their documentation).
If someone could point me in the right direction to updated and current code or a library from Apple I am missing that will specifically address this issue, it would be much appreciated.
-
El Tomato over 6 yearsAppKit for iOS? That's unheard of.
-
flaaghara over 6 yearsYou are right, updated library
-
-
flaaghara over 6 yearsThanks but I specifically said in my question that I do not want to use an outside library.
-
flaaghara over 6 years"Unexpectedly found nil while unwrapping an optional value." If using a notification, how does the function know which text field I am talking about? I have multiple and you aren't telling the function in your example how to unwrap textField.
-
SJ3040 over 6 yearsTextField in my example is not an optional so no need to unwrap it. I think you missed it's a IBOutlet. For multiple textfield you can figure out the first responder, calculate offsetY which is done in code and animate you whole view accordingly.
-
Saurabh Prajapati over 6 yearsdo not forget to remove observer in "viewWillDisappear"
-
vofili about 5 yearsthis is an awesome alternative @jaydeep Patel
-
Yonathan Goriachnick almost 3 yearsThe bust answer. Needs some adjustments but really the best working solution.