iOS: heightForRowAtIndexPath no se dispara durante el desplazamiento

Estoy escribiendo una aplicación simple para iOS usando Xcode4, que usa una vista de tabla para mostrar una list de historias (obtenida de una URL). Estoy mostrando los títulos de la historia como UILabels, y como una subvista de la celda de la tabla.

Estoy heightForRowAtIndexPath para calcular la altura correcta para las celdas según la longitud de cada título de la historia. Estoy agregando la label a la celda en cellForRowAtIndexPath . Cuando ejecuto la aplicación en el simulador, todo funciona bien. Sin embargo: cuando me desploop hacia abajo y me desploop hacia arriba, las tags se desorientan. Se truncan y se sobrecargan. Depuré un poco y encontré que el método heightForRowAtIndexPath no se dispara durante el desplazamiento, por lo que las alturas de las celdas no se vuelven a calcular y, por lo tanto, el text de la label se desborda y se vuelve feo. Aquí está el código relevante:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"]; cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; [cell autorelease]; } /* NOTE: code to load trimmedTitle dynamically is snipped */ NSString* trimmedTitle; UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(280.0f, MAXFLOAT); CGSize labelSize = [trimmedTitle sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; UILabel* tempLabel = [[UILabel alloc] initWithFrame:CGRectMake(60, 0, 230, labelSize.height)]; tempLabel.lineBreakMode = UILineBreakModeWordWrap; tempLabel.text = trimmedTitle; tempLabel.numberOfLines = 0; [cell.contentView addSubview:tempLabel]; [tempLabel release]; return cell; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { NSString* cellText; // code to load cellText dynamically is snipped off UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT); CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; return labelSize.height + 20; } 

En situaciones como estas, suelo calcular previamente las alturas de todas mis filas, almacenarlas en una matriz y, a continuación, simplemente devolver esas alturas en heightForRowAtIndexPath . De esta manera, el tableview conoce la altura de cada celda y las celdas se ajustan a esa altura incluso después de la reutilización. No sé cómo forzar un cálculo de la altura de la celda más allá de search cuando una celda será visible y volver a cargarla, lo que parece demasiado costoso.

Actualización : algún código de ejemplo:

Tengo un método llamado - (void)calculateHeights que hace el mismo cálculo que tenía en heightForRowAtIndexPath , pero almacena el resultado en mi array mutable heights_ ivar:

 - (void)calculateHeights { [heights_ removeAllObjects] for (Widget *myWidget in modelWidgetArray) { NSString* cellText; // code to load cellText dynamically is snipped off UIFont *cellFont = [UIFont fontWithName:@"Georgia" size:14.0]; CGSize constraintSize = CGSizeMake(230.0f, MAXFLOAT); CGSize labelSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap]; [heights_ addObject:[NSNumber numberWithFloat:labelSize.height + 20.0f]]; } } 

Y luego en heightForRowAtIndexPath , dada una vista de tabla de 1 sección:

 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [heights_ objectAtIndex:[indexPath row]]; } 

Si la vista de la tabla tiene más de una sección, necesitará hacer algunos cálculos para convertir a la matriz de heights_ unidimensionales y viceversa. Además, siempre que -reloadData , -reloadData .

La -tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath método -tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath antes de componer la vista de desplazamiento.

El propósito de invocar este método antes de invocar -tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath y no dispararse durante el desplazamiento es que la vista de tabla ( que se henetworkinga de UIScrollView ) necesita conocer la altura completa de contentView . Una vez que la vista de tabla conoce toda la altura, -reloadData en caching la altura antes de llamar -reloadData

Su problema significa que debe borrar el contenido en -setNeedLayout y call -setNeedLayout de la -setNeedLayout para distribuir todos los contenidos nuevos.

Puede usar tags para su label para evitar problemas entre ellos.

 UILabel *label= (UILabel*)[cell viewWithTag:2]; label.lineBreakMode = UILineBreakModeWordWrap; label.numberOfLines = 0;