user1904273
user1904273

Reputation: 4764

Keep Bottom of TableView Visible When Keyboard Shows With Autolayout in Swift

I have a tableview with a textview for entering text immediately below it similar to Apple Messages. When the user begins to enter text and the keyboard appears, I want the following behavior similar to IOS Messages.

  1. If the keyboard will not cover anything, the visible part of the tableview remains unchanged.

  2. If the keyboard will cover something, the tableview moves up just enough so that its bottom-most filled cell is just above the keyboard.

Because I'm using autolayout, I currently have a constraint between the tableview and the textview below it. Also, the project has IQKeyboard which manages a lot of other views involving textfields and textviews.

The constraint combined with IQKeyboard accomplishes 2. When the keyboard appears, the keyboard pushes the textview up. The textview pushes the tableview up. So if the tableview is fully populated, you see the last cell of the tableview above the textview above the keyboard as desired.

However, 2. is not working.

if the tableview is not filled, the keyboard pushes up the textview which pushes up the tableview so that you longer see the top of the tableview.

I have tried adjusting the contentOffset property of the tableview when the Keyboard Shows and this sort of works but the tableview initially moves up before coming back down. I think this is because the notification to change the offset property does not fire until after the keyboard has begun to move up.

I also tried adjusting the tableview height to its content but this causes the textview to expand to fill the difference due to constraints.

Content offset approach - problem is that content offset adjusts too late
//register for keyboard notifications and in handler:
if let infoKey  = notification.userInfo?[UIKeyboardFrameEndUserInfoKey],
   let rawFrame = (infoKey as AnyObject).cgRectValue {
     let keyboardFrame = view.convert(rawFrame, from: nil)
     self.heightKeyboard = keyboardFrame.size.height
     UIView.animate(withDuration: 0.2, animations: {
             self.tableView.contentInset = UIEdgeInsetsMake(self.heightKeyboard!, 0, 0, 0);
     })
}

Can anyone suggest a way to mimic the behavior of Apple Messages? Thanks in advance for any suggestions.

Upvotes: 0

Views: 2082

Answers (1)

DonMag
DonMag

Reputation: 77423

One approach:

  • constrain the top of the tableView to the top of the view
  • constrain the bottom of the tableView to the top of the textField
  • constrain the bottom of the textField to the bottom of the view
  • create an @IBOutlet for the textField's bottom constraint

When the keyboard is shown, change the .constant of the textField's bottom constraint to the height of the keyboard view.

This will move the textField up, and because it's top is constrained to the bottom of the tableView, it will also move the tableView's bottom edge up.

Then scroll to the bottom of the tableView.

Layout:

enter image description here

Initial hierarchy, with 20 rows (scrolled to the bottom):

enter image description here

Hierarchy view (tableView background color set to green, so we can see its frame):

enter image description here

View after the keyboard is shown:

enter image description here

Hierarchy after the keyboard is shown:

enter image description here

Little tough to see from static screen caps, but the frame of the green rectangle (the tableView background) is now shorter... the user can still scroll up and down to see all the rows, but the bottom of the tableView is still constrained to the top of the textField.

When you the keyboard is dismissed, set the .constant of the textField's bottom constraint back to Zero.

You can see a full, working example project up on GitHub: https://github.com/DonMag/KBAdjust

Upvotes: 1

Related Questions