0

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.

Before message sent

It jumps up in between the "Hi" and "Testing" messages.

After message sent

Michael Hsu
  • 950
  • 1
  • 9
  • 25
  • usually you would just move the whole view of the view controller up by the keyboard height for a chat app where the text entry is at the very bottom – Scriptable Mar 22 '18 at 15:11
  • I tried doing that, but then how would I allow the user to see all of the messages? If I shift the whole table view up, then it'll slide under the header. – Michael Hsu Mar 22 '18 at 15:14
  • I was thinking of just shifting it up, then adjusting contentInset, but then the scrollbar would scroll off of view, and inserting rows would be a problem too. – Michael Hsu Mar 22 '18 at 15:39

1 Answers1

0

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.

  • Basically every ui updation should be done on main thread and after reloading data we just scrolled the tableview to the bottom position of the last cell. – Ankush Bhatia Mar 22 '18 at 19:27
  • so when I update constraints or use UIView.animate, I should use DispatchQueue.main.async with it? Sorry, I'm still a beginner. – Michael Hsu Mar 22 '18 at 19:31
  • In case of animations as soon as you pass the block it is called immediately so you need not to put these in any queues. OS handles all the animations itself in general. But here is the catch, suppose you are executing something in the background thread and you need to update UI using animations then you have to come back to main queue to perform the animation. It all depends on how your code is being executed. – Ankush Bhatia Mar 22 '18 at 19:37