Celda personalizada para la aplicación de iOS: XIB o encoding ?. Problemas con la altura y las posiciones de los frameworks

Estoy intentando build un UITableCellView personalizado que contenga múltiples subviews pero ahora mismo estoy luchando con solo dos de ellos (los más grandes): un UIImageView (no me importaría usar UIWebView en su lugar ya que las imágenes vienen de Internet) y una UITextView que debe presentar todo el text sin desplazarse, de una vez. Con este escenario, empecé a build una celda personalizada utilizando el file XIB y subclasificando UITableCellView (desactivación automática de la desconnection):

introduzca la descripción de la imagen aquí

He agregado dos nuevas properties (IBOutlet) a una class personalizada (bastante simple):

@interface NewsFeedPostCell : UITableViewCell<UITextViewDelegate> { UIImageView *picView; UITextView *postContent; } @property IBOutlet UIImageView *picView; @property IBOutlet UITextView *postContent; @end 

y después de eso los estoy usando para rellenar los datos (obtengo algunas cosas de iTunes que devuelven una hermosa JSON @ " http://itunes.apple.com/search?term=ice%20age&country=us&entity=movie " ) Por el momento estoy centrado en mostrar los datos correctamente sin get los tamaños exactos para cada celda (aparte del tamaño de los texts que son diferentes), pero tengo muchos problemas: el contenido no se muestra correctamente porque no se muestra todo el text, primero la fila no muestra la image, etc. Leí mucho aquí en stackoverflow pero estoy empezando a sentir dolor por las diferentes maneras en que las personas lo resuelven porque he probado también usando solo el código para getlo y he tenido algo similar o peor aún

Mi principal pregunta / queja aquí es cuál podría ser la mejor manera de build una tabla compleja con celdas personalizadas con diferentes alturas y subidas y cómo calcular los tamaños, o mejor que eso, cuándo y dónde (en el código) ya que se llama a heightForRowAtIndexPath antes de que haya descargado imágenes para get sus tamaños. Hay un montón de properties para layouts, networkingibujar y "ajuste de tamaño", pero ninguno de ellos parece funcionar como supuse que tenían que hacerlo. Siento que estoy demasiado lejos para saber cómo funciona el layout en la aplicación iOS y me parece que los elementos de la interfaz de usuario no tienen flexibilidad en absoluto 🙁

Este es el código fuente utilizado (por cierto, estoy usando la biblioteca AFNetworking para get imágenes y cargarlas en UIImageView):

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *simpleTableIdentifier = @"PostCell"; NewsFeedPostCell *cell; NSDictionary *post = [self.posts objectAtIndex:indexPath.row]; NSString *postText = [post objectForKey:@"longDescription"]; cell= (NewsFeedPostCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier]; if (cell == nil) { NSArray *nib = [[NSBundle mainBundle] loadNibNamed:@"NewsFeedCell" owner:self options:nil]; cell = [nib objectAtIndex:0]; } CGRect picFrame = cell.picView.frame; picFrame = CGRectMake(100, 0, 300, 100); [cell.picView setFrame:picFrame]; [cell.picView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[post objectForKey:@"artworkUrl100"]]] placeholderImage:nil success:^(NSURLRequest *request , NSHTTPURLResponse *response , UIImage *image ){ NSLog(@"Loaded successfully: %d", [response statusCode]); [cell.picView setImage:image]; [cell.picView sizeToFit]; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){ NSLog(@"failed loading: %@", error); } ]; CGSize stringSize = [self calculateTextHeight:postText]; CGRect postFrame = cell.postContent.frame; postFrame = CGRectMake(10, 100, 300, stringSize.height); cell.postContent.frame = postFrame; cell.postContent.autoresizingMask = UIViewAutoresizingFlexibleHeight; cell.postContent.font = [UIFont systemFontOfSize:POST_CONTENT_FONT_SIZE]; cell.postContent.text= postText; [cell.postContent setContentInset:UIEdgeInsetsZero]; [cell.postContent sizeThatFits:cell.postContent.contentSize]; return cell; } 

Vea los problemas en las capturas de pantalla (estoy usando un simulador de iOS que simula un dispositivo de retina de 3.5 "y que usa como objective para comstackr la aplicación iOS SDK 6.1)

Primera fila (la image está debajo de la barra superior; debe desplazarse para verla) Esta es la primera fila

Otra fila que no muestra el text correctamente, tengo que desplazarme hacia abajo / arriba para getla: introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí

Y es imposible completar el text de la última fila: introduzca la descripción de la imagen aquí

La mejor manera de hacer celdas personalizadas con diferentes alturas es:

crear un NSMutableArray para celdas:

 @property (nonatomic,retain)NSMutableArray* cellsArray; 

luego en m .:

el primer método que llama es

 -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ 

crea tu celular aquí:

  -(float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ if (!self.cellsArray) { self.cellsArray = [[NSMutableArray alloc]init]; } ListCell* cell = [[ListCell alloc] initWithFrame:CGRectMake(0, 0,, 50)]; // IMPLEMENT your custom cell here, with custom data, with custom,different height: // after add this cell to your array: [self.cellsArray addObject:cell]; // IMPORTANT STEP: set your cell height for the new height: cell.frame = CGRectMake(cell.frame.origin.x, cell.frame.origin.y, 303, yourLastItemInCell.frame.origin.y + yourLastItemInCell.frame.size.height); return cell.frame.size.height; } 

Después de que obtuviste las celdas personalizadas con diferentes alturas:

 #pragma mark - conform to delegates - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 10; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return self.cellsArray[indexPath.row]; } 

Espero que ayude !

Como usted dice, el problema (o al less uno de ellos) es que se llama a heightForRowAtIndexPath antes de que su image y / o text se hayan cargado. La solución de solución rápida es activar una recarga de tabla cuando se completa la carga de datos.

Sin embargo, más fundamentalmente sugiero reestructurar su código para separar su model y verlo. Tal vez tenga una class separada para representar los datos de cada celda (y properties, como la altura del text) y otra class responsable de cargar los datos en ella. Cuando se cargan los datos, su model puede notificar a las classs interesadas (es decir, su UITableView) para recargar las filas necesarias.

Gracias a todos. Probé las suyas y funcionan pero no completamente. El problema con la altura está casi resuelto pero estoy experimentando un problema con la visualización de la celda porque, cuando son un poco más largos, no se muestran completamente (imágenes ni texts). Las capturas de pantalla muestran filas primera y segunda. Puede ver que hasta que se desplace hacia abajo un poco, la segunda fila no está visible y, para verlo, debe desplazarse hacia abajo hasta que la image solo se muestre parcialmente. Esto no es tan fácil como pensé al principio. Gracias por sus comentarios y ayuda.

introduzca la descripción de la imagen aquíintroduzca la descripción de la imagen aquí

Hablando de código, he usado la solución de incmiko, pero aún tengo problemas para download imágenes porque debería hacerlo de forma asíncrona y después de que Table View se deba volver a dibujar para ajustar el tamaño de las imágenes, pero no estoy seguro de cómo hacerlo.

Célula personalizada:

 @interface NewsFeedCell : UITableViewCell<UITextViewDelegate> { UIImageView *picView; UITextView *postContent; float cellHeight; } @property (nonatomic, retain) UIImageView *picView; @property (nonatomic, retain) UITextView *postContent; @property (nonatomic) float cellHeight; //-(id)initWithImageUrlString:(NSString *)imgUrl AndText:(NSString *)postText; -(void)setPostImage:(NSString *)imgUrl; -(void) setPostContenText:(NSString *)postText; -(void) setcontentHeight; -(float) getCellHeight; @end 

La celda personalizada se iniatiliza solo con un TextView ya que parte del contenido futuro no tendrá ninguna image (sé que tendré que cuidarlo al calcular la altura y el tamaño de la vista de contenido).

 - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code [self setFrame:CGRectMake(CELL_LEFT_MARGIN, 0, CELL_TOTAL_WIDTH, 50)]; postContent = [[UITextView alloc] initWithFrame:CGRectMake(CELL_LEFT_MARGIN, 0, CELL_TOTAL_WIDTH, 100)]; [self.contentView addSubview:postContent]; } return self; } 

Estoy usando AFNetworking para download imágenes:

 -(void)setPostImage:(NSString *)imgUrl { picView =[[UIImageView alloc] initWithFrame:CGRectMake(0,0, 50, 50)]; [picView setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imgUrl]] placeholderImage:nil success:^(NSURLRequest *request , NSHTTPURLResponse *response , UIImage *pic ) { //NSLog(@"Loaded successfully: %d", [response statusCode]); [picView setImage:pic]; [self.contentView addSubview:picView]; CGRect frame = CGRectMake((self.bounds.size.width/2-pic.size.width/2), 0, pic.size.width, pic.size.height); [picView setFrame:frame]; frame = self.contentView.frame; frame.size.height = picView.frame.size.height; self.contentView.frame = frame; } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error){ NSLog(@"failed loading: %@", error); } ]; } -(void)setPostContenText:(NSString *)postText { CGSize stringSize = [self calculateTextHeight:postText]; CGRect frame = postContent.frame; frame = CGRectMake(CELL_LEFT_MARGIN, picView.frame.origin.y+picView.frame.size.height, CELL_TOTAL_WIDTH, stringSize.height); postContent.frame = frame; postContent.autoresizingMask = UIViewAutoresizingFlexibleHeight; postContent.font = [UIFont systemFontOfSize:POST_CONTENT_FONT_SIZE]; postContent.text= postText; postContent.textColor=[UIColor blackColor]; [postContent setContentInset:UIEdgeInsetsZero]; [postContent setBackgroundColor:[UIColor whiteColor]]; [postContent setEditable:NO]; frame.size.height = stringSize.height + 5.0f; } -(void) setcontentHeight { if(self) { CGRect frame = self.contentView.frame; frame = self.contentView.frame; frame.size.height = postContent.frame.size.height + picView.frame.size.height; self.contentView.frame = frame; self.cellHeight = self.contentView.frame.size.height + 10; NSLog(@"picView height: %f", picView.frame.size.height); NSLog(@"textview height: %f", postContent.frame.size.height); } else self.cellHeight = 44.0f; } 

Y controller que llama a las celdas personalizadas:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (self.cellsArray && self.cellsArray.count) { return self.cellsArray.count; } else { return 0; } } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return [self.cellsArray[indexPath.row] getCellHeight]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return self.cellsArray[indexPath.row]; } #pragma mark - -(void)createCellArray { static NSString *simpleTableIdentifier = @"PostCell"; if (!self.cellsArray) { self.cellsArray = [[NSMutableArray alloc]init]; } for(NSDictionary *post in posts) { NSString *postText = [post objectForKey:@"longDescription"];//[posts objectAtIndex:indexPath.row]; NewsFeedCell *cell= [[NewsFeedCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier]; if(cell) { [cell setPostImage:[post objectForKey:@"artworkUrl100"]]; [cell setPostContenText:postText]; [cell setcontentHeight]; [cellsArray addObject:cell]; } } }