Etiqueta de longitud variable, alturas de fila de vista de tabla y layout automático

Hay mucha información buena sobre SO y en otros lugares sobre cómo calcular la altura necesaria para una fila UITableView dependiendo del tamaño de una subvista. El ejemplo típico, y el que estoy aplicando aquí, es una celda que contiene una label con text de longitud variable.

introduzca la descripción de la imagen aquí

El consejo habitual es usar el sizeWithFont:constrainedToSize:lineBreakMode: en el heightViewForRowAtIndexPath de heightForRowAtIndexPath: Pero la mayoría de los ejemplos que he visto usan un número "mágico" basado en el ancho conocido de la label.

 CGSize constraint = CGSizeMake(224.0, MAXFLOAT); //224 is known to be the width available CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; 

Algunos ejemplos mejores podrían usar los límites de la tabla y, a continuación, restar numbers mágicos o constantes para las otras vistas de la celda, que son al less un poco más claras (y funcionan mejor si los límites cambian en rotation, etc.).

 CGSize constraint = CGSizeMake(self.tableview.bounds.size.width - 20 - 10 - 36 - 20, MAXFLOAT); //each non-label width subtracted CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:NSLineBreakByWordWrapping]; 

Este es el enfoque común, pero parece faltar. ¿Quién debe decir que los anchos de las otras subvenciones de la celda, e incluso la fuente, están garantizados para no cambiar (o siempre se cambiarán diligentemente en ambos lugares)?

Decidí que prefiero que la célula sea ​​responsable de proporcionar esta altura. La célula siempre conoce sus attributes. Para lograr esto, primero hice que todo mi código de disposition en la celda se refiera a algunas constantes locales. Luego agregué un método de class a mi class de celda personalizada, que puede devolver la altura requerida para una determinada pieza de text, en function de su propia fuente y de las constantes de tamaño.

 + (CGFloat)heightRequinetworkingForText:(NSString *)text usingWidth:(CGFloat)width { //a class method that tells the caller how much height is needed for the provided text, based on the cell's size and font constants CGSize constraintSize = CGSizeMake(width - kMargin - kGap - kMargin - kCheckboxWidth, MAXFLOAT); CGRect bounds = [text boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:self.labelFont} context:nil]; return bounds.size.height; } 

Esto permite que UITableViewController simplemente proporcione el text y el ancho de los límites actuales, (es decir, el ancho de la vista de tabla). La fuente y el layout se pueden cambiar en la subclass de celda y todo sigue "simplemente funcionando".

Pregunta 1

Al igual que una nota al margen, ¿es esto razonable? ¿Hay una mejor manera de lograr lo mismo?

Pregunta 2

Aquí está el problema principal que estoy teniendo con este enfoque (y el más estándar). Cuando la celda está en su modo de edición, el ancho de la label cambia para acomodar los accesorios de edición. Como la altura de la fila es constante y la label usa la disposition automática, aumenta su altura.

introduzca la descripción de la imagen aquí

El comportamiento requerido es que la altura de la label permanezca constante y el truncamiento debe usarse cuando sea necesario.

¿Dónde y cómo puedo implementar esto? ¿Debería estar haciendo algo en el set de la celda? Tal vez agregando otra restricción para restringir la altura y activar el truncamiento, con lo contrario aplicado cuando se edita == NO? ¿Qué pasa con el patrón 'deslizar para eliminar'? ¿No creo que esto desencadena la edición de set? ¿Qué pasa con layoutSubview? ¿Podría hacer algo allí?

Probé muchas cosas: lo más cercano que obtuve fue anotar layoutSubviews, probar si el usuario había entrado al modo de edición y, de ser así, capturar la altura intrínseca de la label primero y luego agregar una restricción temporal para forzarla (que luego se eliminó cuando saliendo del modo de edición). Funcionó bien a exception de algunos casos extremos.

Pero luego empecé a pensar en el layout automático un poco más. ¿Qué estaba tratando de lograr? No quería que la label fuera más alta cuando se networkingujo su ancho. Esa es una restricción bastante directa:

 [self.contentView addConstraint:[NSLayoutConstraint constraintWithItem:self.label attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self.contentView attribute:NSLayoutAttributeHeight multiplier:1 constant:0]]; 

Agregar esta restricción adicional funciona bien. Tenga en count que también cambio el modo de salto de línea para truncar en la edición:

introduzca la descripción de la imagen aquí