Search code examples
iosswiftuitableviewmessaging

swift messaging app, uitableview not responding correctly to keyboard?


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


Solution

  • 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.