Agregar una UIView a una UITableViewCell mediante cell.contentView.

Tengo una class llamada GraphView que extiende UIView que básicamente dibuja un pequeño gráfico de líneas. Necesito uno de estos charts en la parte superior de cada sección en mi UITableView. Entonces intenté creando una celda separada en la parte superior de una de mis secciones y luego en esa celda lo hice:

[cell.contentView addSubview:graphView]; [graphView release]; 

Pero cuando me desploop hacia abajo, es como si el gráfico fuera glitchy y aparece en puntos aleatorios a lo largo de UITableView. ¿Alguien tiene ideas o ideas? ¿Hay una mejor manera de incorporar otra UIView en la parte superior de cada sección en mi UITableView?

 - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { //NSLog(@"cellForrowAtIndexPath"); static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; } cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.textLabel.font = [UIFont systemFontOfSize:12]; cell.detailTextLabel.font = [UIFont systemFontOfSize:12]; NSString *str1, *str2; if(indexPath.section == 0) { if(indexPath.row == 0) { str1 = @""; str2 = @""; S7GraphView *graphView = [[S7GraphView alloc] initWithFrame:CGRectMake(10,0,310,100)]; graphView.dataSource = self; NSNumberFormatter *numberFormatter = [NSNumberFormatter new]; [numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle]; [numberFormatter setMinimumFractionDigits:0]; [numberFormatter setMaximumFractionDigits:0]; graphView.yValuesFormatter = numberFormatter; NSDateFormatter *dateFormatter = [NSDateFormatter new]; [dateFormatter setTimeStyle:NSDateFormatterNoStyle]; [dateFormatter setDateStyle:NSDateFormatterShortStyle]; graphView.xValuesFormatter = dateFormatter; [dateFormatter release]; [numberFormatter release]; graphView.backgroundColor = [UIColor whiteColor]; graphView.drawAxisX = NO; graphView.drawAxisY = YES; graphView.drawGridX = NO; graphView.drawGridY = YES; graphView.xValuesColor = [UIColor blackColor]; graphView.yValuesColor = [UIColor blackColor]; graphView.gridXColor = [UIColor blackColor]; graphView.gridYColor = [UIColor blackColor]; graphView.drawInfo = NO; graphView.info = @"Load"; graphView.infoColor = [UIColor whiteColor]; //When you need to update the data, make this call: //[graphView reloadData]; //S7GraphView *graphView = [[S7GraphView alloc] initWithFrame:CGRectMake(10,0,320,300)]; //self.graphView.dataSource = self; [cell.contentView addSubview:graphView]; [graphView release]; } 

He resuelto usar tags:

 - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [theTableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; } else{ [[cell.contentView viewWithTag:500] removeFromSuperview]; } ... graphView.tag = 500; [cell.contentView addSubview:graphView]; } 

Una vista de tabla funciona de manera ligeramente diferente de lo que cabría esperar al principio. Básicamente, solo las celdas que ves están realmente cargadas en la memory. Si lo piensas bien, tiene sentido: si tuvieras 10 000 elementos en tu tabla, todos cargados en memory, tu aplicación se quedará sin memory y se bloqueará bastante rápido.

Cuando se desplaza, sus celdas se crean en time real. La parte confusa: tus celdas no se crean desde cero, en lugar de eso, iOS solo toma una celda que acaba de salir de la pantalla y la envía

 - (UITableViewCell *)tableView:(UITableView *)theTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

de nuevo. Por lo tanto, la subvista que agregó a su celda superior no se eliminará cuando esa celda se reutilice aún más a medida que se desplaza. Respuesta corta: asegúrese de eliminar / restablecer la subvista en la function anterior, de esta manera "reajustará" las celdas usadas que se están reutilizando más abajo en la vista de la tabla.

¿Por qué iOS lo hace de esta manera? Eficiencia: básicamente, es muy costoso crear una celda de vista de tabla. Encontrar el ancho, el color, dibujar la forma … + mucho más requiere mucha potencia y time de la CPU. Es mucho más eficiente reutilizar las células cada vez que empezar desde cero.

Por lo tanto, restablezca solo los campos necesarios de una celda en su function de creación de celda. De esta manera, tendrá un desplazamiento suave y rápido, pero las vistas / properties de su celda se restablecerán antes de que la celda se reutilice.

Confuso al principio Sip. Pero definitivamente la mejor manera de hacerlo.

Ok así:

 static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease]; } //now remove any subview a reused cell might have: [cell.contentView.view removeFromSuperview]; //and in part of the method, you'll need to create the subview if the cell is in the top row. if (indexPath.row == 0) { [cell.contentView.view addSubview:graphView.view]; } 

Podría ser un poco diferente en su caso debido a la vista de charts en lugar de una UIView. Pero esta es definitivamente la base de lo que debería ser.

¡Espero que ayude!

Esto es, como pensé, un problema de reutilización celular:

cada vez, tableView:cellForRowAtIndexPath: se ejecuta, agrega otra instancia de GraphView. En combinación con la reutilización de celdas, donde los objects de celda se reasignan a otros índices, esto genera un gran problema.

Debes agregar subyenes solo dentro de if (cell == nil) .

Deberá realizar un seguimiento o sus GraphViews por separado. O agregándolos a un NSDictionary con los índices path como key, o subclarando UITableViewCell.