I've got a UITableView that is being populated by an NSFetchedResultsController.
On the initial load of the table I would like the Cells to be animated in but I would like to do a little bit more custom animation than
[tableView insertRowsAtIndexPaths:withRowAnimation:];
Allows. Specifically I would like to slow down the animations and have them fly in from the side in a specific way. I have not been able to achieve this by UITableViewRowAnimation constants. Is there a way to use Core Animation to do exactly what I want or do I need to stick with UIKit animations in this specific instance?
Thanks for any help!
Joel
NEWEST SOLUTION (2017-12-12)
Adding a Swift 4.0 version of the animate method. It should then be implemented in the same way as the solution below:
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)
}
}
}
NEWER SOLUTION (2015-09-05)
Adding a Swift 2.0 version of the animate method. It should then be implemented in the same way as the solution below:
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)
}
}
}
NEW SOLUTION (2014-09-28)
I reworked the solution a bit to make the implementation more easier and to make it work with iOS8. All you need to do is to add this animate
method in your TableViewController and call it whenever you want it to animate (for instance, in your reload method, but you could call it at any time):
- (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)];
}];
}];
}
Again, change the animation how you like. This particular code will animate the cells in from the right at a slow rate.
OLD SOLUTION (2013-06-06)
You can do this by implementing your own UITableView and overriding the insertRowsAtIndexPaths method. Here is an example of how that could look like where the cells will be pushed from the right, really slowly (1 second animation):
- (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];
}
}
You can play around with the animations yourself. This method will not be called automatically by the table view so you have to override the reloadData method in your table view delegate and call this method yourself.
COMMENT
The reloadData method should look something like this:
- (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];
}
materik's answer haven't worked for me with iOS 7.1 SDK, I've got nil after calling [self cellForRowAtIndexPath:indexPath];
Here's my code in subclass of 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];
}
}
}
}
Use this:
-(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)];
}];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With