26

Tengo un UITableView que está siendo llenado por NSFetchedResultsController.¿Se pueden hacer animaciones personalizadas para las inserciones de celdas UITableView?

En la carga inicial de la mesa me gustaría que las células sean animados en, pero me gustaría hacer la animación un poco más a medida que

[tableView insertRowsAtIndexPaths:withRowAnimation:]; 

Permite. Específicamente, me gustaría reducir la velocidad de las animaciones y hacer que vuelen desde un lado de una manera específica. No he podido lograr esto con las constantes UITableViewRowAnimation. ¿Hay alguna manera de usar Core Animation para hacer exactamente lo que quiero o necesito para seguir con las animaciones de UIKit en esta instancia específica?

¡Gracias por cualquier ayuda!

Joel

Respuesta

33

nueva solución (2017-12-12)

Adición de un Swift versión 4,0 del método animado. A continuación, debe aplicarse de la misma manera como la solución a continuación:

func animate() { 
    for cell in self.tableView.visibleCells { 
     cell.frame = CGRect(x: self.tableView.frame.size.width, y: cell.frame.origin.y, width: cell.frame.size.width, height: cell.frame.size.height) 
     UIView.animate(withDuration: 1.0) { 
      cell.frame = CGRect(x: 0, y: cell.frame.origin.y, width: cell.frame.size.width, height: cell.frame.size.height) 
     } 
    } 
} 

NUEVOS SOLUCIÓN (2015-09-05)

Adición de una versión Swift 2.0 del método animado. A continuación, debe aplicarse de la misma manera como la solución a continuación:

func animate() { 
    for cell in self.tableView.visibleCells { 
     cell.frame = CGRectMake(320, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height) 
     UIView.animateWithDuration(1.0) { 
      cell.frame = CGRectMake(0, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height) 
     } 
    } 
} 

NUEVA SOLUCIÓN (2014-09-28)

volví a trabajar la solución un poco para hacer la aplicación más fácil y para hacer que funcione con iOS8. Todo lo que necesita hacer es añadir este método animate en su TableViewController y llamarlo siempre que lo desee para animar (por ejemplo, en el método de recarga, pero se le puede llamar en cualquier momento):

- (void)animate 
{ 
    [[self.tableView visibleCells] enumerateObjectsUsingBlock:^(UITableViewCell *cell, NSUInteger idx, BOOL *stop) { 
     [cell setFrame:CGRectMake(320, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 
     [UIView animateWithDuration:1 animations:^{ 
      [cell setFrame:CGRectMake(0, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 
     }]; 
    }]; 
} 

De nuevo , cambia la animación como quieras Este código particular animará las celdas desde la derecha a una velocidad lenta.

antigua solución (2013-06-06)

Usted puede hacer esto mediante la implementación de su propio UITableView y reemplazando el método insertRowsAtIndexPaths. Aquí es un ejemplo de cómo podría parecerse a la que las células serán empujados desde la derecha, muy lentamente (1 segundo de animación):

- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation 
{ 
    for (NSIndexPath *indexPath in indexPaths) 
    { 
     UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]; 
     [cell setFrame:CGRectMake(320, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 

     [UIView beginAnimations:NULL context:nil]; 
     [UIView setAnimationDuration:1]; 
     [cell setFrame:CGRectMake(0, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 
     [UIView commitAnimations]; 
    } 
} 

se puede jugar con las animaciones usted mismo. La vista de tabla no llamará automáticamente a este método, por lo que debe anular el método reloadData en su delegado de vista de tabla y llamar a este método usted mismo.

COMENTARIO

El método reloadData debería ser algo como esto:

- (void)reloadData 
{ 
    [super reloadData]; 
    NSMutableArray *indexPaths = [[NSMutableArray alloc] init]; 
    for (int i = 0; i < [_data count]; i++) 
     [indexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]]; 
    [self insertRowsAtIndexPaths:indexPaths withRowAnimation:0]; 
} 
+0

Gracias! Funciona de maravilla. –

+0

¿Se trata simplemente de anular el método 'insertRowsAtIndexPaths: withRowAnimation:'? Cuando lo reemplazo y luego llamo con el método 'beginUpdates:' y 'endUpdates:', la aplicación falla en '[UITableView _endCellAnimationsWithContext:]' –

+0

Vea mi edición ... –

8

de Materik answer no han trabajado para mí con iOS 7.1 SDK, tengo nula después de llamar [self cellForRowAtIndexPath:indexPath];

Aquí está mi código en la subclase de UITableView:

- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths 
       withRowAnimation:(UITableViewRowAnimation)animation 
{ 
    [super insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone]; 
    [self endUpdates]; // Populates UITableView with data 
    [self beginUpdates]; 
    for (NSIndexPath *indexPath in indexPaths) { 
     __block UITableViewCell *cell = [super cellForRowAtIndexPath:indexPath]; 
     if (cell) { // If indexPath isn't visible we'll get nil here 
      // Custom animation 
      CGRect frame = cell.frame; 
      frame.origin.x = cell.frame.size.width; 
      cell.frame = frame; 
      frame.origin.x = 0; 
      void (^animationsBlock)() = ^{ 
       cell.frame = frame; 
      }; 
      if ([[UIView class] respondsToSelector: 
       @selector(animateWithDuration:delay:usingSpringWithDamping: 
          initialSpringVelocity:options:animations:completion:)]) { 
       [UIView animateWithDuration:0.3 
             delay:0 
        usingSpringWithDamping:0.5 
         initialSpringVelocity:0 
            options:0 
           animations:animationsBlock 
           completion:NULL]; 
      } else { 
       [UIView animateWithDuration:0.3 
             delay:0 
            options:UIViewAnimationOptionCurveEaseIn 
           animations:animationsBlock 
           completion:NULL]; 
      } 
     } 
    } 
} 
+0

Estoy insertando una fila en la parte superior pero obtengo una celda nula en [super cellForRowAtIndexPath: indexPath]. Lo es porque aún no está visible si sí, entonces ¿cómo puedo hacer la animación para la inserción – harpreetSingh

+0

@harpreetSingh lo siento, hace mucho tiempo que he trabajado en este proyecto ¿Obtiene 'nil' cell después de anular' - [UITableView insertRowsAtIndexPaths: withRowAnimation:] '? De todos modos, te recomiendo que pruebes el enfoque de [respuesta actualizada al alza] (http: // stackoverflow.com/a/14182059/1226304) y si no funciona, crea un proyecto de prueba solo con este problema y compártelo aquí. Alguien que me incluya puede que lo revise y te ayude a solucionarlo. – derpoliuk

+0

Tengo una solución. La animación no estaba sucediendo porque estaba llamando [tableView reloadData] justo después de ella. Después de eliminar eso, funciona como un amuleto. Gracias amigo – harpreetSingh

1

Utilice esta:

-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath{ 
     [cell setFrame:CGRectMake(320, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 
      [UIView animateWithDuration:2 animations:^{ 
       [cell setFrame:CGRectMake(100, cell.frame.origin.y, cell.frame.size.width, cell.frame.size.height)]; 

      }]; 

} 
+3

el problema con este enfoque es que siempre volverá a cargar las células reutilizables. con la animación cuando el usuario se desplaza (no solo para la inserción). –

0

Swift versión 3.0 de respuesta de Mattias Eriksson

func animate() { 
    for cell in tblView.visibleCells { 
     cell.frame = CGRect(x:320, y:cell.frame.origin.y, width:cell.frame.size.width, height:cell.frame.size.height) 
      UIView.animate(withDuration: 1.0) { 
       cell.frame = CGRect(x:0, y:cell.frame.origin.y, width:cell.frame.size.width, height:cell.frame.size.height) 
      } 
    } 
} 
Cuestiones relacionadas