Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

289
Visualizações
TableView calculates wrong estimatedHeightForRowAt

I'm making a chat like application, where the tableView displays dynamic height cells.


The cells have their views&subviews constrained in the right way

So that the AutoLayout can predict the height of the cells

(Top, Bottom, Leading, Trailing)


But still - as you can see in the video - the scroll indicator bar shows that wrong heights were calculated:

It recalculates the heights when a new row is appearing.

Video: https://youtu.be/5ydA5yV2O-Q

(On the second attempt to scroll down everything is fine)


Code:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

It is a simple problem. Can someone help me out?

Update 1.0

Added github:

https://github.com/krptia/Test

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

But still - as you can see in the video - the scroll indicator bar shows that wrong heights were calculated:

So what you want is precise content height.

For that purpose, you cannot use static estimatedRowHeight. You should implement more correct estimation like below.

    ...

    var sampleCell: WorldMessageCell?

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.register(UINib(nibName: "WorldMessageCell", bundle: nil), forCellReuseIdentifier: "WorldMessageCell")

        sampleCell = UINib(nibName: "WorldMessageCell", bundle: nil).instantiate(withOwner: WorldMessageCell.self, options: nil)[0] as? WorldMessageCell
    }

    ...

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        if let cell = sampleCell {
            let text = self.textForRowAt(indexPath)
            // note: this is because of "constrain to margins", which value is actually set after estimation. Do not use them to remove below
            let margin = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 20)
            // without "constrain to margins"
            // let margin = cell.contentView.layoutMargins 
            let maxSize = CGSize(width: tableView.frame.size.width - margin.left - margin.right,
                                 height: CGFloat.greatestFiniteMagnitude)
            let attributes: [NSAttributedString.Key: Any]? = [NSAttributedString.Key.font: cell.messageLabel.font]
            let size: CGRect = (text as NSString).boundingRect(with: maxSize,
                                                                 options: [.usesLineFragmentOrigin], attributes: attributes, context: nil)
            return size.height + margin.top + margin.bottom
        }
        return 100
    }

This is too precise (actually real row height) and maybe slow, but you can do more approximate estimation for optimization.

over 4 years ago · Santiago Trujillo Relatório

0

You need to set tableFooterView to empty.

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.tableFooterView = UIView()
    // your staff
}
over 4 years ago · Santiago Trujillo Relatório

0

The problem is with your estimatedHeightForRowAt method. As the name implies it gives the estimated height to the table so that it can have some idea about the scrollable content until the actual content will be displayed. The more accurate value will result in a more smooth scrolling and height estimation.

You should set this value to big enough so that it can represent the height of your cell with the maximum content. In your case 650 is working fine.

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 650
}

The result would be far better with this approach.

Also, there is no need to implement delegate method for height until you want a variation on index bases. You can simply set table view property.

tableView.estimatedRowHeight = 650.0
tableView.rowHeight = .automaticDimension

Optimization

One more thing I noticed in your demo project. You've used too many if-else in your cellForRowAtIndexPath which is making it little slower. Try to minimize that. I've done some refinement to this, and it improves the performance.

  1. Define an array which holds your message text.

    var messages = ["Lorem ipsum,"many more",.....]

  2. Replace your cellForRowAt indexPath with below:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { var cell : WorldMessageCell cell = tableView.dequeueReusableCell(withIdentifier: "WorldMessageCell", for: indexPath) as! WorldMessageCell if indexPath.row < 14 { cell.messageLabel.text = messages[indexPath.row] } else if indexPath.row >= 14 && indexPath.row != 27 { cell.messageLabel.text = messages[14] } else if indexPath.row == 27 { cell.messageLabel.text = messages.last } return cell }

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda