2010-11-21 14 views
7

Tengo UITableView que usa UITableViewCell s personalizado. Las celdas pueden tener uno de tres tipos de imágenes de fondo (establecidas en la propiedad .backgroundView.image de cada celda): superior, central o inferior. Las imágenes superior e inferior son para la primera y la última celda, y tienen esquinas redondeadas (muy parecido a las células agrupadas de UITableView). Todas las otras celdas "centrales" dentro del UITableView tienen una imagen de fondo media rectangular.Recargando UITableViewCell personalizado después de reordenar las celdas

Mi problema es que cuando la reordenación de las células en el modo Editar la UITableView 's las células no se actualizan con una imagen de fondo diferente en función de su nueva ubicación. Por ejemplo, si muevo la primera celda al centro de la tabla, aún conserva su imagen de fondo "superior" original (con esquinas redondeadas) y la nueva celda que aparece en la parte superior de la vista de tabla todavía tiene su "centro" original imagen de fondo, que todo parece un poco extraño.

Puedo evitar esto haciendo un reloadData en la vista de tabla, pero esto tiene el problema de no dar una bonita y graciosa animación de los cambios. Observé que al reordenar un estándar agrupado UITableView tan pronto como se mueve/arrastra una celda, la imagen de fondo en las celdas relevantes cambia (incluso antes de que la celda movida se haya caído en su nueva ubicación), lo que se ve muy bien. Me gustaría lograr lo mismo.

Para este fin, he implementado tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath que se llama cada vez que se arrastra una fila en la vista de tabla. Dentro de esto, he intentado varios métodos para configurar el backgroundView.image, incluida la configuración directa de la imagen y luego también explícitamente diciéndole que vuelva a dibujar la celda y/o imagen usando setNeedsLayout y setNeedsDisplay pero nada parece hacer que la celda vuelva a dibujarse. Tengo NSLog 'ged los resultados de estos cambios y parecen comprometerse con la celda, ya que los valores correctos aparecen en el NSLog, pero la celda simplemente no parece actualizarse en la pantalla.

Si alguien pudiera señalar lo que estoy haciendo mal, o sugerir una forma mejor de lograr un resultado de trabajo, estaría muy agradecido. ¡Gracias!

EDIT: el siguiente código fue retirado de la generosidad y formateado para que pueda ser más fácil de digerir:

UIImage *rowBackground; 
UIImage *selectionBackground; 
NSInteger sectionRows = [_tableView numberOfRowsInSection:[indexPath section]]; 
NSInteger row = [indexPath row]; 
if (row == 0 && row == sectionRows - 1) 
{ 
    rowBackground = [UIImage imageNamed:@"field_title_bkg.png"]; 
    selectionBackground = [UIImage imageNamed:@"field_title_bkg.png"]; 
} 
else if (row == 0) 
{ 
    rowBackground = [UIImage imageNamed:@"table_row_top_bkg.png"]; 
    selectionBackground = [UIImage imageNamed:@"table_row_top_bkg.png"]; 
} 
else if (row == sectionRows - 1) 
{ 
    rowBackground = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 
    selectionBackground = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 
} 
else 
{ 
    rowBackground = [UIImage imageNamed:@"table_row_bkg.png"]; 
    selectionBackground = [UIImage imageNamed:@"table_row_bkg.png"]; 
} 
UIImageView *rowBackGroundImageView = [[UIImageView alloc] initWithImage:rowBackground]; 
UIImageView *rowBackGroundSelectionImageView = [[UIImageView alloc] initWithImage:selectionBackground]; 
if (row != sectionRows - 1) 
{ 
    UIImageView *sep = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell_separator.png"]]; 
    [sep setFrame:CGRectMake(20, 56, 280, 1)]; 
    [rowBackGroundImageView addSubview:sep]; 
} 
[cell setBackgroundView:rowBackGroundImageView]; 
[rowBackGroundImageView release]; 
+0

Puede intentar enmascarar la vista de tabla con otra vista encima. Entonces no necesitarás imágenes de fondo para las células. – Eimantas

+0

¿Podría explicar esta idea un poco más? No entiendo muy bien cómo funcionaría eso. – Skoota

+0

Una pregunta relacionada: http://stackoverflow.com/questions/7338161/update-old-new-top-bottom-cells-backgroundview-when-inserting-deleting-top-bott – an0

Respuesta

0

no he probado a mí mismo, pero ¿por qué no probar su valor indexPath.row en el método cellForRowAtIndexPath y proporcionar los diferentes valores de backgroundView.image para la primera y la última fila?

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

Espero que esto ayude. Saludos, Rog

+0

Hola Rog. Eso es lo que estoy haciendo actualmente, pero 'cellForRowAtIndexPath' no se llama cuando la fila se mueve ya que la fila ya está en la pantalla. Intenté llamar manualmente a 'cellForRowAtIndexPath' en el método' tableView: targetIndexPathForMoveFromRowAtIndexPath: toProposedIndexPath', pero no sucede nada (es decir, la celda no se vuelve a cargar/redibujar en la pantalla). – Skoota

1

Si sólo desea volver a cargar unas pocas células en lugar de toda la tabla se pueden utilizar:

reloadRowsAtIndexPaths:withRowAnimation: 

disponible como un método de instancia de UITableView.

+0

Hola Robert. Intenté eso, pero no funcionará en el método 'tableView: targetIndexPathForMoveFromRowAtIndexPath: toProposedIndexPath' (es decir, mientras se arrastra/mueve la fila) y se bloquea con el mensaje de que el número de filas y secciones después de la animación debe coincidir con el número antes de la animación No es sorprendente dado que las filas aún se mueven cuando intentamos llamar a este método. – Skoota

+0

¿Ha intentado realizar la recarga en el método UITableViewDataSource 'tableView: moveRowAtIndexPath: toIndexPath:' en su lugar? Creo que se llama a uno después de que se complete el movimiento. –

+0

Hola Robert. Perdon por la respuesta tardia. Intenté esto también, pero causa un comportamiento extraño. Si solo vuelvo a cargar 'toIndexPath', la fila en' fromIndexPath' desaparecerá por completo. ¡Si vuelvo a cargar ambas vías de indexación, realmente se convertirá en un cable de heno y empezará a poner varias copias de las células una encima de la otra! – Skoota

0

(this solution only works for the reordering of rows within the same section. It'll fail when dragging and dropping rows to a different section)

que tenían el mismo problema al actualizar el texto detalle la etiqueta de una célula después de ser reordenado.

Lo resuelto con el siguiente código:

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
UITableViewCell* cell = [self.table cellForRowAtIndexPath:fromIndexPath]; 
cell.detailTextLabel.text = @"NEW STRING"; 
} 

Tenga en cuenta que usted tiene que actualizar la celda en fromIndexPath, porque parece que el estado interno de la tableview no se actualiza hasta que devuelve este método . Si obtiene la celda al toIndexPath, después de reordenar los acabados, verá que la celda vecina se actualiza. (arriba o abajo).

1

Prueba esto:

[tableView beginUpdates]; 
[tableView endUpdates]; 
0

las API para la recarga parcialmente filas en el SDK de iOS que no funciona bien (por eso PPL siguen este post aquí)

termino usando temporizador para recargar la datos completos después de reordenar la animación termina. Funciona para mí.

- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath 
{ 
    //things to be done when reordering rows 
    .... 


    //issue a timer to reload data 
    NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval: 0.1 
              target: self 
              selector:@selector(updateRow) 
              userInfo: nil repeats:NO]; 


} 


-(void) updateRow 
{ 

    [self.table reloadData]; 

} 
+0

no estoy seguro de que necesite usar un temporizador; simplemente puede usar '-performSelectorOnMainThread:' – nielsbot

4

Escriba a continuación el código en su proyecto y debería funcionar de acuerdo con las expectativas.

- (NSIndexPath *)tableView:(UITableView *)tableView 
targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath 
     toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath 
{ 
    NSInteger sectionRows = [tableView numberOfRowsInSection:[sourceIndexPath section]]; 

    UITableViewCell *sourceCell = [tableView cellForRowAtIndexPath:sourceIndexPath]; 
    UITableViewCell *destCell = [tableView cellForRowAtIndexPath:proposedDestinationIndexPath]; 

    if(sourceIndexPath.row == 0 && proposedDestinationIndexPath.row == 1) 
    { 
     ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"]; 

     if(proposedDestinationIndexPath.row == sectionRows - 1) 
      ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 
     else 
      ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"]; 
    } 

    else if(sourceIndexPath.row == sectionRows - 1 && proposedDestinationIndexPath.row == sectionRows - 2) 
    { 
     ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 

     if(proposedDestinationIndexPath.row == 0) 
      ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"]; 
     else 
      ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"]; 
    } 

    else if(proposedDestinationIndexPath.row == 0) 
    { 
     ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"]; 

     destCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:proposedDestinationIndexPath.section]]; 
     if(sectionRows == 2) 
      ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 
     else 
      ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"]; 
    } 

    else if(proposedDestinationIndexPath.row == sectionRows - 1) 
    { 
     ((UIImageView *)sourceCell.backgroundView).image = [UIImage imageNamed:@"table_bottom_row_bkg.png"]; 

     destCell = [tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:sectionRows - 1 inSection:proposedDestinationIndexPath.section]]; 
     if(sectionRows == 2) 
      ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_top_bkg.png"]; 
     else 
      ((UIImageView *)destCell.backgroundView).image = [UIImage imageNamed:@"table_row_bkg.png"]; 
    } 

    return proposedDestinationIndexPath; 
} 
+0

¡Esto funcionó a la perfección! Mi vista de accesorios parece haber desaparecido, pero estaba pensando en hacer una personalizada de todos modos. –

+0

Por lo tanto, si arrastra una fila a una fila diferente, luego decide que no la quiere allí antes de soltar el arrastre, la imagen cambia a la imagen de celda incorrecta: / –

Cuestiones relacionadas