Autolayout ignora el detalle de varias líneas Text Label al calcular la altura UITableViewCell (todos los styles)

Por lo tanto, estoy intentando utilizar los styles incorporados UITableViewCell, específicamente UITableViewCellStyleSubtitle, con una (línea) de text de línea simple pero detalleLabel de múltiples líneas . Pero la altura de la celda (auto) calculada es consistentemente demasiado corta, y parece ignorar que hay más de 1 línea de detalle.

He intentado usar numberOfLines = 0, estimatedRowHeight, UITableViewAutomaticDimension, prefernetworkingMaxWidthLayout, etc., pero en todas las permutaciones, el comportamiento -de hecho para todos los styles UITableViewCell- es que el cálculo de altura de celda UITableViewAutomaticDimension contabilizará correctamente una label de text multilínea (¡sí! ), pero incorrectamente asume que el detailTextlabel es como máximo una sola línea (¡no!). En consecuencia, las celdas con un detalleTextLabel de varias líneas son demasiado cortas y, por lo tanto, el contenido de la celda se dertwig sobre la parte superior e inferior de la celda.

introduzca la descripción de la imagen aquí

Publicé una aplicación de testing rápida que muestra este comportamiento en GitHub aquí . Agregar líneas adicionales de text está bien, todos los styles de celda aumentan de forma adecuada en altura para adaptarse, pero agregar líneas adicionales de detalle no hace nada para cambiar la altura de la celda y rápidamente provoca que el contenido se derrame; el text + detalle están dispuestos correctamente y juntos se centran correctamente en el centro de la celda (por lo que en ese sentido layoutSubviews funciona correctamente), pero la altura de la celda en general no cambia.

Casi parece que no hay restricciones reales superiores e inferiores entre cell.contentView y las tags, y en cambio la altura de la celda se calcula directamente desde la altura de la (posiblemente varias líneas) textLabel y (solo una línea) detailTextLabel , y luego todo está centrado sobre el centro de la celda … Nuevamente, textLabel multilínea está bien, y no estoy haciendo nada diferente entre textLabel y detailTextLabel, pero solo el primero (correctamente) ajusta la altura de la celda.

Entonces, mi pregunta es si es posible utilizar los styles incorporados UITableViewCell para mostrar de forma fiable detallesTextLabels de varias líneas , ¿o simplemente no es posible y necesita crear una subclass personalizada en su lugar? [o, casi de manera equivalente, sin tener que replace las vistas de layout en una subclass y volver a cablear todas las restricciones manualmente].


[4 de mayo de 2016] Conclusión: a partir del detalle de varias líneas de iOS9, TextLabels no funciona como se espera con UITableViewAutomaticDimension; la celda será consistentemente demasiado corta y el text / detalle se dertwigrá sobre la parte superior e inferior. O debe calcular manualmente la altura de celda correcta usted mismo, o crear y diseñar su propia subclass UITableViewCell personalizada equivalente, o subclass (ver mi respuesta a continuación) UITableViewCell y corregir systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: para devolver la altura correcta [recomendado]

Otras investigaciones (ver UITableViewCellTest ) indican que cuando UITableViewAutomaticDimension está habilitado, el sistema llama a -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: para calcular la altura de la celda, y que esto casi ignora la altura de detailTextLabel en su cálculo (error?). Como resultado, para UITableViewCellStyleSubtitle, la altura de la celda siempre será demasiado corta [una sola línea detailTextLabel puede no dertwigrse completamente sobre la celda, pero eso es solo debido a los márgenes superior e inferior existentes], y para UITableViewCellStyleValue1 o UITableViewCellStyleValue2 la altura será demasiado corto cada vez que detailTextLabel sea ​​más alto (por ejemplo, más líneas) que textLabel . Todo esto es un punto discutible para UITableViewCellStyleDefault que no tiene detailTextLabel.

Mi solución fue subclass y corregir con:

 - (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority verticalFittingPriority:(UILayoutPriority)verticalFittingPriority { [self layoutIfNeeded]; CGSize size = [super systemLayoutSizeFittingSize:targetSize withHorizontalFittingPriority:horizontalFittingPriority verticalFittingPriority:verticalFittingPriority]; CGFloat detailHeight = CGRectGetHeight(self.detailTextLabel.frame); if (detailHeight) { // if no detailTextLabel (eg style = Default) then no adjustment necessary // Determine UITableViewCellStyle by looking at textLabel vs detailTextLabel layout if (CGRectGetMinX(self.detailTextLabel.frame) > CGRectGetMinX(self.textLabel.frame)) { // style = Value1 or Value2 CGFloat textHeight = CGRectGetHeight(self.textLabel.frame); // If detailTextLabel taller than textLabel then add difference to cell height if (detailHeight > textHeight) size.height += detailHeight - textHeight; } else { // style = Subtitle, so always add subtitle height size.height += detailHeight; } } return size; } 

Y en el controller de vista:

 - (void)viewDidLoad { [super viewDidLoad]; self.tableView.estimatedRowHeight = 44.0; self.tableView.rowHeight = UITableViewAutomaticDimension; } 

Puede extraer la subclass completa de aquí: MultilineTableViewCell

Hasta ahora, esta solución parece funcionar bien, y me ha permitido utilizar con éxito el incorporado UITableViewCellStyles con text y detalles multilínea , en celdas autodimensionadas con soporte de tipo dynamic. Esto evita el problema (y el desorder) de calcular manualmente las alturas de celda deseadas en tableView:heightForRowAtIndexPath: o tener que crear layouts de celdas personalizadas.

Respuesta de @tiritea en Swift 3 (¡Gracias de nuevo !: D)

 // When UITableViewAutomaticDimension is enabled the system calls // -systemLayoutSizeFittingSize:withHorizontalFittingPriority:verticalFittingPriority: to calculate the cell height. // Unfortunately, it ignores the height of the detailTextLabel in its computation (bug !?). // As a result, for UITableViewCellStyleSubtitle the cell height is always going to be too short. // So we override to include detailTextLabel height. // Cnetworkingit: http://stackoverflow.com/a/37016869/467588 override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { self.layoutIfNeeded() var size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority) if let textLabel = self.textLabel, let detailTextLabel = self.detailTextLabel { let detailHeight = detailTextLabel.frame.size.height if detailTextLabel.frame.origin.x > textLabel.frame.origin.x { // style = Value1 or Value2 let textHeight = textLabel.frame.size.height if (detailHeight > textHeight) { size.height += detailHeight - textHeight } } else { // style = Subtitle, so always add subtitle height size.height += detailHeight } } return size } 

Desde mi experiencia, las celdas integradas no son compatibles con el cambio de tamaño automático con restricciones, creo que la mejor solución es crear una celda personalizada, realmente lleva un par de minutos y no es necesario replace layoutSubview, es muy simple. Simplemente cambie el tipo de celda en el IB a personalizado, arrastre una label, establezca restricciones (en el IB), establezca el número de filas, cree una subclass, cambie la class de celdas en el IB a su subclass, cree una salida en el IB subclass y esa es la mayor parte del trabajo, estoy seguro de que hay una gran cantidad de tutoriales en la networking que puede seguir.

Swift 3

Después de leer varias respuestas, he utilizado el siguiente método para get información detallada sobre el text UITableViewAutomaticDimension. Utilice la celda de estilo básica con la label de título solamente y use la cadena atribuida para la vista Texto y detalle de text. No olvide cambiar el estilo de la celda de vista de tabla de Subtítulo a Básico.

 func makeAttributedString(title: String, subtitle: String) -> NSAttributedString { let titleAttributes = [NSFontAttributeName: UIFont.prefernetworkingFont(forTextStyle: .headline), NSForegroundColorAttributeName: UIColor.purple] let subtitleAttributes = [NSFontAttributeName: UIFont.prefernetworkingFont(forTextStyle: .subheadline)] let titleString = NSMutableAttributedString(string: "\(title)\n", attributes: titleAttributes) let subtitleString = NSAttributedString(string: subtitle, attributes: subtitleAttributes) titleString.append(subtitleString) return titleString } 

Cómo usar en cellforrowatindexpath

 cell.textLabel?.attributedText = makeAttributedString(title: "Your Title", subtitle: "Your detail text label text here") 

Agregar líneas siguientes en viewdidload

  YourTableView.estimatedRowHeight = UITableViewAutomaticDimension YourTableView.rowHeight = UITableViewAutomaticDimension YourTableView.setNeedsLayout() YourTableView.layoutIfNeeded() 

Parece que Apple ha resuelto este error en iOS 11.