with uitableviewcell tutorial multiple example different custom ios uitableview ios8 autolayout ios-autolayout

ios - uitableviewcell - Las alturas de celda dinámica UITableView solo se corrigen después de un desplazamiento



uitableview with multiple custom cells swift (22)

Tengo una UITableView con una UITableViewCell personalizada definida en un guión gráfico mediante el diseño automático. La celda tiene varios UILabels multilínea.

El UITableView parece calcular correctamente las alturas de las celdas, pero para las primeras celdas esa altura no se divide correctamente entre las etiquetas. Después de desplazarse un poco, todo funciona como se esperaba (incluso las celdas que inicialmente eran incorrectas).

- (void)viewDidLoad { [super viewDidLoad] // ... self.tableView.rowHeight = UITableViewAutomaticDimension; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; // ... // Set label.text for variable length string. return cell; }

¿Hay algo que pueda estar perdiendo, que está causando que el diseño automático no sea capaz de hacer su trabajo las primeras veces?

Creé un proyecto de muestra que demuestra este comportamiento.


Agregar [cell layoutIfNeeded] en cellForRowAtIndexPath no funciona para celdas que se desplazan inicialmente fuera de vista.

Tampoco lo hace prefabricando con [cell setNeedsLayout] .

Todavía tiene que desplazar ciertas celdas y volver a la vista para que cambien de tamaño correctamente.

Esto es bastante frustrante ya que la mayoría de los desarrolladores tienen las células Dynamic Type, AutoLayout y Self-Sizing funcionando correctamente, a excepción de este caso molesto. Este error afecta a todos mis controladores de mesa "más altos".


Agregue una restricción para todo el contenido dentro de una celda personalizada de la vista de tabla, luego estime la altura de la fila de la vista de tabla y configure la altura de la fila en la dimensión automática con una carga viewdid:

override func viewDidLoad() { super.viewDidLoad() tableView.estimatedRowHeight = 70 tableView.rowHeight = UITableViewAutomaticDimension }

Para solucionar ese problema de carga inicial, aplique el método layoutIfNeeded en una celda de vista de tabla personalizada:

class CustomTableViewCell: UITableViewCell { override func awakeFromNib() { super.awakeFromNib() self.layoutIfNeeded() // Initialization code } }


El problema es que las celdas iniciales se cargan antes de que tengamos una altura de fila válida. La solución consiste en forzar la recarga de una tabla cuando aparece la vista.

- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self.tableView reloadData]; }


En Swift 3. Tuve que llamar a self.layoutIfNeeded () cada vez que actualicé el texto de la celda reutilizable.

import UIKit import SnapKit class CommentTableViewCell: UITableViewCell { static let reuseIdentifier = "CommentTableViewCell" var comment: Comment! { didSet { textLbl.attributedText = comment.attributedTextToDisplay() self.layoutIfNeeded() //This is a fix to make propper automatic dimentions (height). } } internal var textLbl = UILabel() override func layoutSubviews() { super.layoutSubviews() if textLbl.superview == nil { textLbl.numberOfLines = 0 textLbl.lineBreakMode = .byWordWrapping self.contentView.addSubview(textLbl) textLbl.snp.makeConstraints({ (make) in make.left.equalTo(contentView.snp.left).inset(10) make.right.equalTo(contentView.snp.right).inset(10) make.top.equalTo(contentView.snp.top).inset(10) make.bottom.equalTo(contentView.snp.bottom).inset(10) }) } } }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let comment = comments[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: CommentTableViewCell.reuseIdentifier, for: indexPath) as! CommentTableViewCell cell.selectionStyle = .none cell.comment = comment return cell }

commentsTableView.rowHeight = UITableViewAutomaticDimension commentsTableView.estimatedRowHeight = 140


En mi caso, el problema con la altura de la celda tiene lugar después de que se carga la vista de tabla inicial, y se lleva a cabo una acción del usuario (tocando un botón en una celda que tiene el efecto de cambiar la altura de la celda). No he podido hacer que la celda cambie su altura a menos que lo haga:

[self.tableView reloadData];

lo intenté

[cell layoutIfNeeded];

pero eso no funcionó.


En mi caso, estaba actualizando en otro ciclo. Así que la altura de tableViewCell se actualizó después de establecer etiquetaTexto. Borré el bloque asíncrono.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier:Identifier, for: indexPath) // Check your cycle if update cycle is same or not // DispatchQueue.main.async { cell.label.text = nil // } }


En mi caso, la última línea de UILabel se truncó cuando se mostró la celda por primera vez. Sucedió bastante al azar y la única forma de ajustarlo correctamente era desplazar la celda de la vista y recuperarla. Intenté todas las soluciones posibles mostradas hasta el momento (layoutIfNeeded..reloadData) pero nada funcionó para mí. El truco fue establecer "Autoshrink" en Minimuum Font Scale (0.5 para mí). Darle una oportunidad


En mi caso, una vista de pila en la celda estaba causando el problema. Es un error aparentemente. Una vez que lo eliminé, el problema fue resuelto.



Esto funcionó para mí cuando otras soluciones similares no lo hicieron:

override func didMoveToSuperview() { super.didMoveToSuperview() layoutIfNeeded() }

Esto parece un error real, ya que estoy muy familiarizado con AutoLayout y con el uso de UITableViewAutomaticDimension; sin embargo, de vez en cuando me encuentro con este problema. Me alegra que finalmente encontré algo que funciona como una solución alternativa.


He intentado la mayoría de las respuestas a esta pregunta y no pude conseguir que ninguna de ellas funcione. La única solución funcional que encontré fue agregar lo siguiente a mi subclase UITableViewController :

override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) UIView.performWithoutAnimation { tableView.beginUpdates() tableView.endUpdates() } }

Se UIView.performWithoutAnimation llamada UIView.performWithoutAnimation , de lo contrario verá la animación de vista de tabla normal cuando se carga el controlador de vista.


Intenté todas las soluciones en esta página, pero al desmarcar las clases de tamaño de uso, al volver a comprobarlo, resolví mi problema.

Editar: Desmarcar clases de tamaño causa muchos problemas en el guión gráfico, así que probé con otra solución. ViewDidLoad ViewWillAppear métodos ViewDidLoad y ViewWillAppear del controlador de vista. Esto resolvió mi problema.


Me encontré con este problema y lo solucioné moviendo mi código de inicialización de vista / etiqueta FROM tableView(willDisplay cell:) TO tableView(cellForRowAt:) .


Ninguna de las soluciones anteriores funcionó, pero sí la siguiente combinación de sugerencias.

Tuve que agregar lo siguiente en viewDidLoad ().

DispatchQueue.main.async { self.tableView.reloadData() self.tableView.setNeedsLayout() self.tableView.layoutIfNeeded() self.tableView.reloadData() }

La combinación anterior de reloadData, setNeedsLayout y layoutIfNeeded funcionó, pero no ninguna otra. Sin embargo, podría ser específico para las celdas del proyecto. Y sí, tuvo que invocar reloadData dos veces para que funcione.

Configure también lo siguiente en viewDidLoad

tableView.rowHeight = UITableViewAutomaticDimension tableView.estimatedRowHeight = MyEstimatedHeight

En tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath)

cell.setNeedsLayout() cell.layoutIfNeeded()


No sé si esto está claramente documentado o no, pero al agregar [cell layoutIfNeeded] antes de devolver la celda se resuelve tu problema.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"TestCell"]; NSUInteger n1 = firstLabelWordCount[indexPath.row]; NSUInteger n2 = secondLabelWordCount[indexPath.row]; [cell setNumberOfWordsForFirstLabel:n1 secondLabel:n2]; [cell layoutIfNeeded]; // <- added return cell; }


Solo asegúrate de no configurar el texto de la etiqueta en el método delegado ''willdisplaycell'' de la vista de tabla. Establezca el texto de etiqueta en el método de delegado ''cellForRowAtindexPath'' para el cálculo dinámico de altura.

De nada :)


Tenía la misma experiencia en uno de mis proyectos.

¿Por qué sucede?

Celda diseñada en Storyboard con algo de ancho para algún dispositivo. Por ejemplo 400px. Por ejemplo, su etiqueta tiene el mismo ancho. Cuando se carga desde el guión gráfico, tiene un ancho de 400 píxeles.

Aquí hay un problema:

tableView:heightForRowAtIndexPath: llamado antes del diseño de la celda son las subvistas.

Entonces calculó la altura para la etiqueta y la celda con un ancho de 400px. Pero se ejecuta en el dispositivo con pantalla, por ejemplo, 320px. Y esta altura calculada automáticamente es incorrecta. Solo porque el layoutSubviews las layoutSubviews ocurre solo después de tableView:heightForRowAtIndexPath: incluso si configura preferredMaxLayoutWidth para su etiqueta manualmente en layoutSubviews esto no ayuda.

Mi solución:

1) Subclase UITableView y anulación dequeueReusableCellWithIdentifier:forIndexPath: Establezca el ancho de la celda igual al ancho de la tabla y forzar el diseño de la celda.

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier forIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [super dequeueReusableCellWithIdentifier:identifier forIndexPath:indexPath]; CGRect cellFrame = cell.frame; cellFrame.size.width = self.frame.size.width; cell.frame = cellFrame; [cell layoutIfNeeded]; return cell; }

2) Subclase UITableViewCell . Establezca preferredMaxLayoutWidth manualmente para sus etiquetas en layoutSubviews . También es necesario configurar manualmente contentView , porque no se distribuye automáticamente después del cambio de marco de celda (no sé por qué, pero lo es)

- (void)layoutSubviews { [super layoutSubviews]; [self.contentView layoutIfNeeded]; self.yourLongTextLabel.preferredMaxLayoutWidth = self.yourLongTextLabel.width; }


Tengo el problema de cambiar el tamaño de la etiqueta, así que solo tengo que hacer
chatTextLabel.text = chatMessage.message chatTextLabel? .updateConstraints () después de configurar el texto

// código completo

func setContent() { chatTextLabel.text = chatMessage.message chatTextLabel?.updateConstraints() let labelTextWidth = (chatTextLabel?.intrinsicContentSize().width) ?? 0 let labelTextHeight = chatTextLabel?.intrinsicContentSize().height guard labelTextWidth < originWidth && labelTextHeight <= singleLineRowheight else { trailingConstraint?.constant = trailingConstant return } trailingConstraint?.constant = trailingConstant + (originWidth - labelTextWidth) }


Tengo un problema similar, en la primera carga, la altura de la fila no se calculó, pero después de un desplazamiento o ir a otra pantalla y vuelvo a esta pantalla, se calculan las filas. En la primera carga, mis artículos se cargan desde Internet y, en la segunda carga, mis artículos se cargan primero desde Core Data y se vuelven a cargar desde Internet, y noté que la altura de las filas se calcula en la recarga desde Internet. Así que noté que cuando se llama a tableView.reloadData () durante la animación de segue (el mismo problema con push y segue actual), no se calculó la altura de la fila. Así que escondí la vista de tabla en la inicialización de la vista y puse un cargador de actividades para evitar un efecto desagradable para el usuario y llamé a tableView.reloadData después de 300ms y ahora el problema está resuelto. Creo que es un error de UIKit, pero esta solución lo soluciona.

Puse estas líneas (Swift 3.0) en mi controlador de finalización de carga de elementos

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: { self.tableView.isHidden = false self.loader.stopAnimating() self.tableView.reloadData() })

Esto explica por qué para algunas personas, pon un reloadData en layoutSubviews resuelve el problema


llamando a cell.layoutIfNeeded() dentro de cellForRowAt me funcionó en ios 10 e ios 11, pero no en ios 9.

para hacer este trabajo en iOS 9 también, llamo a cell.layoutSubviews() y lo hice.


Para mí, ninguno de estos enfoques funcionó, pero descubrí que la etiqueta tenía un Preferred Width establecido en Interface Builder. Eliminar eso (desmarcar "Explícito") y luego usar UITableViewAutomaticDimension funcionó como se esperaba.


- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ // call the method dynamiclabelHeightForText }

utilice el método anterior que devuelve la altura de la fila de forma dinámica. Y asigne la misma altura dinámica a la etiqueta que esté usando.

-(int)dynamiclabelHeightForText:(NSString *)text :(int)width :(UIFont *)font { CGSize maximumLabelSize = CGSizeMake(width,2500); CGSize expectedLabelSize = [text sizeWithFont:font constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping]; return expectedLabelSize.height; }

Este código lo ayuda a encontrar la altura dinámica para el texto que se muestra en la etiqueta.