A similar question is this, except I don't have estimated row heights, I store the actual heights into a dictionary, and either use those, or use UITableViewAutomaticDimension
.
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cellHeightDict[indexPath.row] = cell.frame.size.height
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeightDict[indexPath.row] {
return height
} else {
return UITableViewAutomaticDimension
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let height = cellHeightDict[indexPath.row] {
return height
} else {
return UITableViewAutomaticDimension
}
}
So I'm making a messaging app in Swift 4 right now. When the user shows the keyboard, I want the messages to shift up with the keyboard. So in order to do this, I have a variable keyboardHeight
which correctly gets the height of the keyboard:
let keyboardHeight: CGFloat = ((userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height)!
I change the height of the table view by keyboardHeight
:
self.messageTableViewHeight.constant -= keyboardHeight
So the users can see all of the messages. And to shift up the messages with the keyboard animation, I changed the contentOffset of the table view:
self.messageTableView.contentOffset.y += keyboardHeight
All of this is in a UIView.animationWithDuration
, and I call self.view.layoutIfNeeded()
after, so the shifting and everything works fine. But, when I send a message without scrolling to the bottom, the messageTableView content jumps down??? And it seems to shift down by keyboardHeight
, at least when I eye it. I am using messageTableView.reloadData()
. Here are some images.
It jumps up in between the "Hi" and "Testing" messages.
As soon as you reload the data of the tableview messageTableView.reloadData()
. Every row is reloaded but it is not able to calculate the actual content size somehow. You can try reloading the data in the main queue.
DispatchQueue.main.async {
messageTableView.reloadData()
}
If it still doesn't works, you can add one more thing to the above code. Suppose you have an array of messages in your class. var messages
then you can use this code to display data correctly in the tableview.
DispatchQueue.main.async {
messageTableView.reloadData()
if messages.count > 0 {
let indexPath = IndexPath(row: messages.count - 1, section: 0)
self.messageTableView.scrollToItem(at: indexPath, at: .bottom, animated: true)
}
}
Hope this helps. Happy coding.