¿Cómo calculo heightForRowAtIndexPath cuando la celda aún no está construida todavía?

Pregunta: ¿Cómo se puede calcular mejor la altura de una fila en el método "heightForRowAtIndexPath" de un UITableViewController, dado que:

  1. Estoy usando una subclass personalizada UITableViewCell y el tamaño real de la subvista (por ejemplo, UILabels) se calcula en time de ejecución y depende de cosas tales como si el usuario cambió el tamaño de la fuente
  2. las celdas no están realmente preparadas, parece antes de un "heightForRowAtIndexPath", por lo que no puede confiar en llamar a su celda personalizada instantánea instantánea para consultarla

Lo único que puedo pensar por el momento es: 1. En su subclass UITableViewCell personalizada, cree un método que calcule las alturas de cada subview (por ejemplo, UILabel) que se encuentra en la subclass UITableViewCell; luego, use esta dentro de la subclass de celda cuando esté creando instancias 2. También en la subclass personalizada, cree un método de class que recorra todos los UILabels, llamando al método mencionado anteriormente, para resumir las alturas y, por lo tanto, calcular el alto total de las filas. Tendría que pasar los datos a él (por ejemplo, text en cada uno de los UILabels) 3. En UITableViewController "heightForRowAtIndexPath", entonces debe llamar al método de tipo "calRowHeight" de (2) anterior, pasándole los datos de text de label . Llame de manera efectiva un método de class en su subclass de celda personalizada que sabe cómo calcular la altura total de la fila, pero está utilizando la misma lógica que la celda también necesita …

¿Hay alguna manera más fácil de la que me estoy perdiendo?

Cuando se crea un UITableView y cada vez que lo envía un post de reloadData, el origen de datos se envía un post heightForRowAtIndexPath para cada celda. Entonces, si su table tiene 30 celdas, ese post se envía 30 veces.

Digamos que solo seis de esas 30 celdas están visibles en la pantalla. En ese caso, cuando se crea y cuando se envía un post de recarga de datos, UITableView enviará un post cellForRowAtIndexPath por fila visible, es decir, ese post se enviará seis veces.

¿Por qué Apple lo implementa de esta manera? Parte de la razón es que es casi siempre más barato calcular la altura de una fila que build y completar una celda completa. Y dado que en muchas tables la altura de cada celda será idéntica, a menudo es mucho más barata. Y parte de la razón es porque iOS necesita saber el tamaño de toda la tabla: esto le permite crear las barras de desplazamiento y configurarlo en una vista de desplazamiento, etc.

Si las alturas de las filas varían de tamaño porque contienen cantidades variables de text, puede utilizar uno de los methods SizeWithFont: en la cadena relevante para hacer los cálculos. Esto es más rápido que build una vista y luego medir el resultado. Tenga en count que si cambia la altura de una celda, necesitará volver a cargar toda la tabla (con datos de carga, esto le preguntará al delegado por cada altura, pero solo solicitará celdas visibles) O volverá a cargar selectivamente las filas donde el tamaño tiene cambió

Material adicional Si entiendo la pregunta de seguimiento en el comentario, lo siguiente puede ayudar:

Si está implementando un modo de edición, entonces no es raro que necesite cambiar la altura de las filas de la tabla. Por ejemplo, puede tener text en las filas de la tabla y cuando las celdas se vuelven más estrechas, para dejar espacio para los círculos de eliminación de la derecha, es posible que desee que algunas de las celdas sean más altas para acomodar el text. El enfoque básico aquí es:

  • Asegúrese de que el método tableView: heightForRowAtIndexPath: sabe si está en el modo de edición o no. (Puede preguntar a tableView usando isEditing.) Y luego get el método para devolver la altura correcta, dependiendo de si está en modo de edición o no.

  • En su setEditing: animated: method en UITableViewController (o un UIViewController, cualquiera que esté usando, hay algunas diferencias dependiendo de lo que use, por lo que vale la pena revisar la documentation cuidadosamente) envíe un post de recarga de datos a la tablaView después de haber cambiado su estado . Esto obligará a tableView a tomar las alturas de cada fila y volverá a search las celdas para las filas visibles. El tableView se encarga de hacer que las celdas sean más estrechas cuando ingresas al modo de edición, pero si quieres hacer más trabajo en el layout, hazlo en tableView: cellForRowAtIndex :. Como se señaló anteriormente, la estrategia general es encontrar un medio para calcular la altura que es rápida. Con text sizeWithFont: (y sus variantes) puede hacerlo. Si tiene imágenes, etc., puede tomar sus dimensiones y hacer algunas sums.

  • Además de esos pasos, es posible que también desee desplazarse por la tablaView un poco después de cambiar de modo. Si las alturas de sus filas son diferentes, entonces terminará en la position incorrecta en la tabla después del modo de conmutación. Un enfoque que he tomado aquí es usar performSelector: withObject: afterDelay después de haber recargado la tabla para llamar a un método que hace el ajuste de desplazamiento. Debe usar la demora para permitir que el tableView recoja las nuevas alturas y las nuevas celdas de la tabla. (Puede haber una manera más inteligente de hacer esto). Hago algunas sums para hacer que el ajuste de desplazamiento se base en la diferencia entre el origen.y de tableView: cellForRowAtIndexPath: de la primera fila visible de la celda en la pantalla antes y después de la recarga. Entonces, por ejemplo, para get la position antes de la precarga, algo parecido a esto.

    CGPoint offset = [[self tableView] contentOffset]; NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)]; CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y; 

Lo que he hecho en el pasado, que no estoy seguro es el más eficiente, está dentro de mi método cellForRowAtIndexPath call cellForRowAtIndexPath entonces le pido a la vista de esa celda su altura. He hecho cosas similares para las alturas de encabezado y pie de página. De esta forma, si cambio la celda, el encabezado o el pie de página, no tengo que recordar ir y actualizar el método de altura correspondiente.