UITableView ReloadData Animate Cell UI - ios

In my tableview I need to animate the UI of every cell as the tableview reloads its data.
This needs to a custom animation, not just a fade or default transition.
For example, When tapping the 'Edit' button, in my view, the tableview reloads and each cell updates its UI for this new edit mode.
However, during this reload I have tried using a UIView animation block to update a constraint on a UILabel in my cells, but it will not animate.
Here is the code I run when I call reloadData on my tableview. This is called in cellForRowAtIndexPath method.
[UIView animateWithDuration:0.3f delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^
{
//does not animate
_lblContainerLeftConstraint.constant = 18;
[self setNeedsLayout];
//does animate
_reorderIcon.alpha = 0.5f;
} completion:nil];

I think you need to do this in willDisplayCell rather than cellForRowAtIndexPath since that is called just before display which is as close as you can get to the point it actually appears on screen.
Then set the new constraint value before the animation block and also call [cell.contentView setNeedsLayout] to indicate that layout is needed on the cell content.
Finally only add [cell.contentView layoutIfNeeded] and your alpha change in the animation block which should animate the constraint change over your time period.

Related

Animate UITableViewCell content with AutoLayout when cell appears

I have a UITableView displaying cells. I am using Auto Layout. At some point, I add cells to a section of my tableView and I need to animate a subview of each cells as soon as the cells are visible.
I wrote the following method to animate the content of my cell:
- (void)animateWithPercentage:(NSNumber *)percentage
{
self.progressViewWidthConstraint.constant = [percentage intValue];
[self.progressView setNeedsUpdateConstraints];
[UIView animateWithDuration:0.6f animations:^{
[self.progressView layoutIfNeeded];
}];
}
The method works as expected but I don't know when to call it.
If I call it when - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath is called, I end up animating the whole layout of my cell because the cell did not layout itself before.
I also tried calling it in layoutSubviews but the animation is skipped. I guess at this point it is too early to animate anything.
Any idea where my method should be called?
I've gotten this kind of animation to work by calling performSelector:withObject:afterDelay: in either awakeFromNib or didMoveToSuperview in the custom cell's class. It works even with a delay of 0, but it doesn't work if you just use performSelector. I've noticed that with this method, if some of the cells are off screen, they don't update until they are scrolled on, and the scrolling animation ends. You can get the animation to start as soon as the cell scrolls on screen, even while the scrolling animation is still in progress by using dispatch_async instead.
-(void)awakeFromNib {
dispatch_async(dispatch_get_main_queue(), ^{
[UIView animateWithDuration:2 animations:^{
self.rightCon.constant = 150;
[self.contentView layoutIfNeeded];
} completion:nil];
});
}
Try to put your method in -(void)didMoveToSuperview

Animating auto layout constraint change on UICollectionView

Following on from a previous SO question which I asked, I am attempting to animate the change in height of a UICollectionView (which is yellowBox in the example). This change in height is being triggered by modifying the auto layout constraints on the collection view with the following code:
- (IBAction)expandYellowBox:(id)sender {
[UIView animateWithDuration:0.5
animations:^{
self.yellowBoxHeightConstraint.constant += 50;
[self.view layoutIfNeeded];
}];
}
However, when I call [self.view layoutIfNeeded] this results in the collection view being reloaded, so it flashes visibly to the user. However, I don't want the collection view to reload but instead just to animate its height change. Is there any way to either avoid -layoutIfNeeded reloading the collection view, or an alternative way to animate the constraint height change which doesn't call a method which has the side-effect of reloading the collection view?
In case anyone else encounters this problem, it was because I was actually calling [self.collectionView reloadData] a few lines above the animation block (and didn't notice!). It seems that calling -reloadData and -layoutIfNeeded causes the collection view to flash. Removing the call to -reloadData resolves the problem.

Stop animation in UICollectionView cell

I have a timer that fires every second to refresh data on a UICollectionView cell, sometimes (especially when I rotate the device), the cell starts to blink every second. I want to stop this blink animation. However, I have another animation going on inside the collection view cell, so I don't want to disable all animations on it as this code does:
[UIView setAnimationsEnabled:NO];
[collectionView performBatchUpdates:^{
[collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
[UIView setAnimationsEnabled:YES];
}];
If you don't want animation on reloading collection view, why don't you just call
[collectionView reloadData];
It only reloads all visible cells.
For the animation inside of the collection view cell, why not code more in the cell object?

Stop UITableViewCells from animating when animating a UITableView

I am animating a UITableView. I want the table view to slide open like this:
http://www.youtube.com/watch?v=XIGJLbiRsXE
However, it opens like this:
http://www.youtube.com/watch?v=UJUX-ILCB_0
Notice how the table cells themselves are animating. How can I stop this from happening?
I am using autolayout. The code is thus:
[theView addSubview:theTable];
[theTable reloadData];
[theTable invalidateIntrinsicContentSize];
[UIView animateWithDuration:.33 animations:^{
[theView layoutIfNeeded];
}];
Other details, which may or may not matter:
The table view's parent is a scrollView
I have overridden the intrinsicContentSize of the table view to return the height of all the cells in the table view, so the table view will not scroll
I am changing the datasource of the table view before displaying it
I had a similar problem and was able to stop the animation on the UITableViewCell with the UIView performWithoutAnimation: method.
Use the tableView:willDisplayCell:forRowAtIndexPath: UITableViewDelegate method to get a reference to the cell before it is shown. Then, within the performWithoutAnimation: block, call layoutIfNeeded on the cell object to give it a chance to layout its subviews:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
[UIView performWithoutAnimation:^{
[cell layoutIfNeeded];
}];
}
It might be too late to answer this question but the problem in these kind of cases generally lies in the animation block capturing all the pending layouts scheduled in the next run loop.
The solution that i use is. I call layoutIfNeeded before the animation (before setting or invalidating any constraints) and then inside the animation block.
In your case it will something like this,
[theView addSubview:theTable];
[theTable reloadData];
[theView layoutIfNeeded];
[theTable invalidateIntrinsicContentSize];
[UIView animateWithDuration:.33 animations:^{
[theView layoutIfNeeded];
}];
Have you considered animating instead an opaque subview that is positioned above the table view?
[theView addSubview:theTable];
[theTable reloadData];
UIView *subview = [[UIView alloc] initWithFrame:theTable.frame];
subview.backgroundColor = [UIColor whiteColor];
[theView addSubview:subview];
[UIView animateWithDuration:0.33 animations:^{
subview.frame = CGRectMake(subview.frame.origin.x, subview.frame.size.height, subview.frame.size.width, 0.0);
}];
Try laying out the table first, before you call [theView layoutIfNeeded] inside the animation block. Ideally you could layout piecemeal and for that 0.33 seconds you may get a scroll bar on the table but the goal is to get the table cell layout changes outside of the animated block.

Change image with animation in reused UITableViewCell

In my application I have a feed with posts. Each post is represented by a cell in UITableView. A post has two states: read or unread. Each cell has an UIImageView, which has to display different images based on this state. I set this imageView's image in my table controller's tableView:cellForRowAtIndexPath: method.
I also check visibility of cells while scrolling the table, and, when a cell becomes visible, it's state is changed, so cell's image is changed with animation. This animation, however, is not working properly when cell is reused. First cell to become visible is animated properly, but all cells after the first one already have resulting image when they appear on screen, animation is not fired for them. Here's how I'm doing it:
// This is called when a cell becomes visible
- (void)setIsVisible:(Boolean)isVisible
{
if (isVisible)
{
UIImage * toImage = [UIImage imageNamed:#"img-cell-read.png"];
[UIView transitionWithView:self.myImageView
duration:2.0f
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
self.myImageView.image = toImage;
} completion:NULL];
}
_isVisible = isVisible;
}
I realize that I should somehow reset this animation and start it again when I'm reusing a cell, but I don't understand how exactly should I do it. Also, if I try to animate cell's background color instead of image, it works fine with reusing.
You can override the prepareForReuse method in UITableViewCell to cancel any animations and also reset the image to the original state.
- (void)prepareForReuse{
[super prepareForReuse];
[self.myImageView.layer removeAllAnimations];
self.myImageView.image = YOUR_INITIAL_UIIMAGE;
}
also make sure to import quartz:
#import <QuartzCore/QuartzCore.h>

Resources