2012-07-17 12 views
5

He creado una UITableview con secciones en las que se puede hacer clic. Al hacer clic sobre ellos,insertRowsAtIndexPaths: con scrollToRowAtIndexPath: hace que las secciones de UITableView se oculten incorrectamente

  1. que "expanden" para revelar las células dentro de ellos
  2. los rollos sección click en la parte superior de la vista.

calculo todos los indexpaths a insertar/eliminar las células necesarias y luego insertarlos con el siguiente código:

[self.tableView beginUpdates]; 
[self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation]; 
[self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation]; 
[self.tableView endUpdates]; 
[self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; 

Sólo hay un problema- están ocultos debajo de las secciones de la sección seleccionada. La primera captura de pantalla muestra cómo debe verse la tabla. La segunda captura de pantalla muestra cómo se ve realmente.

Sections Disappear

Si se desplaza hacia arriba (por lo que las secciones ocultas son fuera de la pantalla) y luego se desplaza hacia abajo, las secciones ocultas son llevados de vuelta (una vez más visible). Mi suposición de por qué esto está sucediendo es la siguiente:

Las animaciones de inserción/eliminación están sucediendo al mismo tiempo que el scrollToRowAtIndexPath y confunde el TableView. Si no hubiera hecho scrollToRowAtIndexPath secciones 3 & 4 habría sido fuera de pantalla, por lo que el tableView de alguna manera todavía piensa que son fuera de la pantalla. UITableview oculta celdas/secciones que están fuera de pantalla como una optimización. Si llamo al scrollToRowAtIndexPath con un dispatch_after con 2 segundos, las secciones 3 & 4 se muestran correctamente.

Así que creo que sé por qué ocurre esto, pero no sé cómo corregir/anular esta optimización de UITableview. En realidad, si implemento scrollViewDidEndScrollingAnimation y luego agrego un punto de interrupción en esta función, la aplicación muestra las secciones 3 & 4 correctamente (así es como obtuve la primera captura de pantalla). Pero una vez que continúa desde esta función, las células desaparecen.

El proyecto completo se puede descargar here


detalles de implementación adicionales: Las secciones son secciones UITableView legítimos. He agregado un tapGestureRecognizer que desencadena una devolución de llamada de delegado a la vista de tabla. A continuación se incluye todo el método que abre las secciones.

- (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened 
{ 
    // Open 
    sectionHeaderView.numRows = DefaultNumRows; 
    sectionHeaderView.selected = YES; 
    NSMutableArray *pathsToOpen = [[NSMutableArray alloc] init]; 
    for (int i = 0; i < sectionHeaderView.numRows; i++) 
    { 
     NSIndexPath *pathToOpen = [NSIndexPath indexPathForRow:i inSection:sectionOpened]; 
     [pathsToOpen addObject:pathToOpen]; 
    } 

    // Close 
    NSMutableArray *pathsToClose = [[NSMutableArray alloc] init]; 
    if (openSectionHeader) 
    { 
     for (int i = 0; i < openSectionHeader.numRows; i++) 
     { 
      NSIndexPath *pathToClose = [NSIndexPath indexPathForRow:i inSection:openSectionHeader.section]; 
      [pathsToClose addObject:pathToClose]; 
     } 
    } 

    // Set Correct Animation if section's already open 
    UITableViewRowAnimation insertAnimation = UITableViewRowAnimationBottom; 
    UITableViewRowAnimation deleteAnimation = UITableViewRowAnimationTop; 
    if (!openSectionHeader || sectionOpened < openSectionHeader.section) 
    { 
     insertAnimation = UITableViewRowAnimationTop; 
     deleteAnimation = UITableViewRowAnimationBottom; 
    } 

    openSectionHeader.numRows = 0; 
    openSectionHeader.selected = NO; 
    openSectionHeader = sectionHeaderView; 


    [self.tableView beginUpdates]; 
    [self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation]; 
    [self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation]; 
    [self.tableView endUpdates]; 
    [self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; 
} 
+0

Creo que será mejor que utilices el MVC provisto por Apple. Todo lo que tiene que hacer es agregar/eliminar datos en su origen de datos y no tocar las filas de la vista de tabla – divol

+0

Incluya un poco más de su proyecto en la pregunta, en lugar de esperar una descarga; por ejemplo, cómo calcula las rutas de índice para agregar/eliminar, y son sus encabezados de sección de cosas de "Sección X" o solo son celdas? Sería una mejor pregunta independiente si no dependiera tanto de la descarga de su proyecto. – jrturton

+0

Creo que tu suposición es correcta también. ¿Puedes intentar volver a cargar las filas en el método de delegado de scroll ended? – jrturton

Respuesta

6

De lo que puedo decir, el problema se produce al volver una vista en sección que ya ha sido utilizado. En lugar de:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section 
{ 
    return [self.sectionHeaderViews objectAtIndex:section]; 
} 

consigo ningún problema si se crea un nuevo punto de vista cada vez:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section{ 
    SectionHeaderView *sectionHeaderView = [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName]; 
    sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", section]; 

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)]; 
    [sectionHeaderView addGestureRecognizer:tapRecognizer]; 
    sectionHeaderView.section = section; 
    sectionHeaderView.delegate = self; 
    return sectionHeaderView; 
} 

Es posible que esto está ocurriendo porque usted está utilizando [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName]; para crear encabezados de sección y aferrarse a ellas en una matriz, para la que no creo que se haya creado UITableViewCell, pero no estoy seguro. Es posible que desee considerar antes de UITableViewCell para las vistas de sección y en su lugar utilizar algo más (tal vez un UIImageView con un UILabel). O simplemente no puede almacenar las vistas de sección en una matriz ... la forma en que actualmente tiene configurado su código, no necesita la matriz y la creación de una nueva vista es lo suficientemente trivial que no tiene que preocuparse por ello.

4

@ AaronHayman responde (e IMO, la aceptación y la recompensa deben ir a él, tal como están - ¡esto no encajó en un comentario!), pero iría más lejos - no deberías estar usando una celda en absoluto para el encabezado de sección, y no debería usar el mecanismo de dequeue para esencialmente cargar un plumín.

No se supone que las vistas de encabezado de sección sean celdas, y puede obtener efectos imprevistos al usarlas en lugar de vistas regulares, especialmente si se deducen: la tabla mantiene una lista de estas celdas reutilizables cuando lo hace y los recicla cuando salen de la pantalla, pero los encabezados de sección no son reutilizables, tiene uno por sección.

En el proyecto de ejemplo, he cambiado la superclase de SectionHeaderView ser un UIView llano, y cambiaron su método de createSectionHeaderViews para cargar directamente desde las puntas de ahí:

NSMutableArray *sectionHeaderViews = [[NSMutableArray alloc] init]; 
    UINib *headerNib = [UINib nibWithNibName:SectionHeaderView_NibName bundle:nil]; 
    for (int i = 0; i < 5; i++) 
    { 
     SectionHeaderView *sectionHeaderView = [[headerNib instantiateWithOwner:nil options:nil] objectAtIndex:0]; 
     sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", i]; 

     UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)]; 
     [sectionHeaderView addGestureRecognizer:tapRecognizer]; 
     sectionHeaderView.section = i; 
     sectionHeaderView.delegate = self; 

     [sectionHeaderViews addObject:sectionHeaderView]; 
    } 
    self.sectionHeaderViews = sectionHeaderViews; 

También comentado el registro para la línea de reutilización desde su viewDidLoad. Esto evita que los encabezados de sección desaparezcan.

+0

Buena idea que le muestra cómo crear una instancia de la vista desde un Nib. Por lo general, creo todos mis puntos de vista en el código, así que ni siquiera pensé en eso. –

Cuestiones relacionadas