Estoy creando una aplicación similar a un chat, donde tableView muestra celdas de altura dinámicas.
Las celdas tienen sus vistas y subvistas restringidas de la manera correcta
Para que AutoLayout pueda predecir la altura de las celdas
(Superior, Inferior, Principal, Final)
Pero aún así , como puede ver en el video, la barra indicadora de desplazamiento muestra que se calcularon alturas incorrectas:
Recalcula las alturas cuando aparece una nueva fila.
Vídeo: https://youtu.be/5ydA5yV2O-Q
(En el segundo intento de desplazarse hacia abajo, todo está bien)
Código:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension } func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return UITableView.automaticDimension }Es un problema sencillo. ¿Alguien me puede ayudar?
Github agregado:
Pero aún así, como puede ver en el video, la barra indicadora de desplazamiento muestra que se calcularon alturas incorrectas:
Entonces, lo que quieres es una altura de contenido precisa.
Para ese propósito, no puede usar static estimatedRowHeight . Debe implementar una estimación más correcta como la siguiente.
... 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 }Esto es demasiado preciso (en realidad, la altura real de la fila) y tal vez lento, pero puede hacer una estimación más aproximada para la optimización.
Debe configurar tableFooterView para que esté vacío.
override func viewDidLoad() { super.viewDidLoad() tableView.tableFooterView = UIView() // your staff }El problema está en el método de la altura estimatedHeightForRowAt para la fila. Como su nombre lo indica, le da la altura estimada a la tabla para que pueda tener una idea sobre el contenido desplazable hasta que se muestre el contenido real. El valor más preciso dará como resultado un desplazamiento y una estimación de la altura más suaves.
Debe establecer este valor lo suficientemente grande para que pueda representar la altura de su celda con el contenido máximo. En tu caso 650 está funcionando bien.
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { return 650 }El resultado sería mucho mejor con este enfoque.
Además, no es necesario implementar el método de delegado para la altura hasta que desee una variación en las bases del índice. Simplemente puede establecer la propiedad de vista de tabla.
tableView.estimatedRowHeight = 650.0 tableView.rowHeight = .automaticDimensionMejoramiento
Una cosa más que noté en su proyecto de demostración. Has usado demasiados if-else en tu cellForRowAtIndexPath , lo que lo hace un poco más lento. Trate de minimizar eso. He hecho algunos refinamientos a esto, y mejora el rendimiento.
Defina una matriz que contenga el texto de su mensaje.
var messages = ["Lorem ipsum,"many more",.....]
Reemplace su cellForRowAt indexPath con lo siguiente:
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 }