Tableview scroll content when keyboard shows
Solution 1
Try keeping the editing index path editingIndexPath Getting index path and scroll tableview to that index path
func keyboardWasShown (notification: NSNotification)
{
println("keyboard was shown")
var info = notification.userInfo
var keyboardSize = info.objectForKey(UIKeyboardFrameBeginUserInfoKey).CGRectValue().size
var contentInsets:UIEdgeInsets
if UIInterfaceOrientationIsPortrait(UIApplication.sharedApplication().statusBarOrientation) {
contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.height, 0.0);
}
else {
contentInsets = UIEdgeInsetsMake(0.0, 0.0, keyboardSize.width, 0.0);
}
myTableView.contentInset = contentInsets
myTableView.scrollToRowAtIndexPath(editingIndexPath, atScrollPosition: .Top, animated: true)
myTableView.scrollIndicatorInsets = myTableView.contentInset
}
Solution 2
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)
}
func keyboardWillShow(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0)
}
}
func keyboardWillHide(_ notification:Notification) {
if let keyboardSize = (notification.userInfo?[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
}
}
Solution 3
For Swift 4.2
In viewDidLoad() of your UIViewController:
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
And implementation of selectors:
@objc private func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height, right: 0)
}
}
@objc private func keyboardWillHide(notification: NSNotification) {
tableView.contentInset = .zero
}
Solution 4
Use this Awesome Extension (Updated for Swift 4.2),
extension UIViewController {
func registerForKeyboardWillShowNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil) {
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: nil, using: { notification -> Void in
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top, left: scrollView.contentInset.left, bottom: keyboardSize.height, right: scrollView.contentInset.right)
scrollView.setContentInsetAndScrollIndicatorInsets(contentInsets)
block?(keyboardSize)
})
}
func registerForKeyboardWillHideNotification(_ scrollView: UIScrollView, usingBlock block: ((CGSize?) -> Void)? = nil) {
_ = NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: nil, using: { notification -> Void in
let userInfo = notification.userInfo!
let keyboardSize = (userInfo[UIResponder.keyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue.size
let contentInsets = UIEdgeInsets(top: scrollView.contentInset.top, left: scrollView.contentInset.left, bottom: 0, right: scrollView.contentInset.right)
scrollView.setContentInsetAndScrollIndicatorInsets(contentInsets)
block?(keyboardSize)
})
}
}
extension UIScrollView {
func setContentInsetAndScrollIndicatorInsets(_ edgeInsets: UIEdgeInsets) {
self.contentInset = edgeInsets
self.scrollIndicatorInsets = edgeInsets
}
}
and use as mentioned below from the respective ViewController,
@IBOutlet weak var tableview: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
registerForKeyboardWillShowNotification(tableview)
registerForKeyboardWillHideNotification(tableview)
/* use the above functions with
block, in case you want the trigger just after the keyboard
hide or show which will return you the keyboard size also.
*/
registerForKeyboardWillShowNotification(tableView) { (keyboardSize) in
print("size 1 - \(keyboardSize!)")
}
registerForKeyboardWillHideNotification(tableView) { (keyboardSize) in
print("size 2 - \(keyboardSize!)")
}
}
Solution 5
For Swift 5.0 and considering iPhone Predictive Text is On
take "keyboardSize.height + tableView.rowHeight" as the bottom of tableview just in case if iPhone Predictive Text is On. In that case, we need to scroll up tableview little more.
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
@objc private func keyboardWillShow(notification: NSNotification) {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height + tableView.rowHeight, right: 0)
}
}
@objc private func keyboardWillHide(notification: NSNotification) {
tableView.contentInset = .zero
}
msalafia
Updated on May 28, 2020Comments
-
msalafia almost 4 years
I have a table view with a text field and a textview. I've implemented this code like suggested by this apple sample code https://developer.apple.com/library/ios/documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/KeyboardManagement/KeyboardManagement.html
@IBOutlet var myTableView: UITableView func keyboardWasShown (notification: NSNotification) { println("keyboard was shown") var info = notification.userInfo var keyboardSize = info.objectForKey(UIKeyboardFrameBeginUserInfoKey).CGRectValue().size myTableView.contentInset = UIEdgeInsetsMake(0, 0, keyboardSize.height, 0) myTableView.scrollIndicatorInsets = myTableView.contentInset } func keyboardWillBeHidden (notification: NSNotification) { println("keyboard will be hidden") myTableView.contentInset = UIEdgeInsetsZero myTableView.scrollIndicatorInsets = UIEdgeInsetsZero } override func viewDidLoad() { super.viewDidLoad() NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWasShown:", name: UIKeyboardDidShowNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil) }
When i click on the "text" of the scroll view go just above the top of the screen, but when i release the keyboard it remains scrolled up. It's just like the insets property can't be modified after the first time. What's my mistake?
-
msalafia almost 10 yearsIt doesn't work! it still remain fixed after first scroll. I don't understand why the assignments at keyboardWillBeHidden function doesnt work. Is it possible because the tableview is built with Interface Builder and maybe there's some particular option?
-
Yatheesha almost 10 years@Andorath Can you pass me the sample ?
-
msalafia almost 10 yearshow can i sand you the sample?
-
Nupur Gupta over 6 yearsI am facing the same issue. Can anyone suggest.
-
Ariel Antonio Fundora over 6 yearsThis is the best answer. Thanks.
-
Aftab Ahmed about 6 yearsThe problem with the above approach is the first click on the table view after setting the contentInset, in the section > 0 points to section = 0. i.e. at didSelect the indexPath values correspond to the values in section 0, though you have clicked on the rows in the section > 0. This happens only for the first click.
-
Disha almost 6 yearsPlease check this link. I hope it will help you code.tutsplus.com/tutorials/…
-
yoninja over 5 yearsSame as the answer of Zany.
-
Gajendra Rawat over 5 yearsPlz also remove notification observer
-
ooxio over 5 yearsI noticed that you may receive wrong height if you first close the keyboard and then open it again. To avoid this, simply use UIKeyboardFrameEndUserInfoKey instead of UIKeyboardFrameBeginUserInfoKey.
-
Peter Kreinz over 5 yearsNice extension. Please update to Swift 4.2 and show an example using the block.Thx.
-
Soumen over 5 yearsUpdated the answer for Swift 4.2
-
John J. Camilleri about 5 yearsThere's a missing
}
there beforeextension UIScrollView
(and the indentation is slightly off) -
John J. Camilleri about 5 yearsReally great extension, but does anyone else notice that the value for the bottom edge inset isn't quite right? I end up with extra dead space between my view and the keyboard (see here). The view is aligned to the safe area. I have to adjust the
keyboardSize.height
value with the functionreturn height - (height > 200 ? 50 : 30)
. -
Ben Shabat almost 5 yearsthis is just working great, just need to add the scroll to row function
-
DisplayName over 4 yearsI removed the DispatchQueue part bc it's not needed. It works for me. Share some of your code.
-
captain_haddock over 4 yearsBest answer, can I also suggest to deinit the notifications, please. deinit { NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) }
-
Kurt Lane almost 4 years
let indexPath:IndexPath = IndexPath(row: #, section: #) tableView.scrollToRow(at: indexPath, at: .bottom, animated: true)
-
Aman Gupta almost 4 yearsI tried the same. But my textfield is not moving up
-
nickdnk almost 3 yearsNote that removing observers is no longer required: stackoverflow.com/a/40339926/1650180
-
tounaobun almost 3 yearsWorks like a charm.
-
paul_f over 2 yearsThis doesn't seem to perform well for me. The first time the keyboard shows it works, but the second time, the value returned by keyboardSize.height is like 100 less.
-
paul_f over 2 yearsDoesn't work at all for me.
-
CyberMew about 2 yearsTake note to remove the observers or there might be a memory leak. See: developer.apple.com/library/archive/releasenotes/Foundation/….