Animate UITableViewCell content with AutoLayout when cell appears - ios

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

Related

UITableView ReloadData Animate Cell UI

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.

How keep uicollectionview scroll at a direction without drag?

I want uicollectionviewcell move like things on assembly line.
Now I use
(void)scrollToItemAtIndexPath:(NSIndexPath *)indexPath atScrollPosition:(UICollectionViewScrollPosition)scrollPosition animated:(BOOL)animated
in a method and in the last of method i make method call it self.
But UICollectionViewCell move and stop and go on.
UICollectionView inherits from UIScrollView, so you can use
// determine point, which you want to scroll
CGPoint scrollPoint = CGPointMake(0, self.tableView.contentSize.height - self.tableView.frame.size.height);
// scroll to it, with custom animation duration
[UIView animateWithDuration:5 animations:^{
[self.tableView setContentOffset:scrollPoint];
// Also you can use scrollToItemAtIndexPath here instead of setContentOffset
}];

How do I animate the inner views of a collection view cell while changing it's size?

I have a collection view, and I'm going for the effect where when a cell is tapped on, it grows to take up the entire screen. To accomplish this, I'm essentially just calling performBatchUpdates inside didSelectItemAtIndexPath, and the sizeForItemAtIndexPath knows to return a larger size for a selected cell. This all works pretty well, the cell grows and shrinks as desired.
The problem is inside of the cell. The collection view cell is made up of a moderately complex view hierarchy managed by constraints. I want the sub views of the cell to grow and shrink with the animating cell. Unfortunately, my subviews are snapping immediately to their new position as the cell slowly animates to it's new size. How can I ensure the content of the cell animates with the cell size?
Here are the two relevant methods from the collection view controller:
- (CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if ([collectionView.indexPathsForSelectedItems containsObject:indexPath])
return CGSizeMake(collectionView.bounds.size.width - 20, collectionView.bounds.size.height - (20 + [self.topLayoutGuide length]));
else
return CGSizeMake(260, 100);
}
- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
[collectionView performBatchUpdates:nil completion:nil];
}
I had exactly the same problem. After many tries, the following code did the trick for me. Calling layoutIfNeed directly after the batch update with a duration of 3.0 (+- the batchupdate duration) animated the constraints.
[self performBatchUpdates:nil completion:nil];
// IndexPath of cell to be expanded
UICollectionViewCell *cell = [self cellForItemAtIndexPath:indexPath];
[UIView animateWithDuration:0.3 animations:^{
[cell.contentView layoutIfNeeded];
}];
I would like to expand on Antoine's answer. Calling performBatchUpdates:completion: inside the animation block will actually set the cell resize duration and match the content resize to it.
[UIView animateWithDuration:0.3 animations:^{
[self performBatchUpdates:^{
// set flags needed for new cell size calculation
} completion:nil];
[collectionView layoutIfNeeded];
}];
This way you can also play with the animation timing or even use spring animations.
I have the same problem. Add these to your subclass of CollectionViewCell. It works for me.
// ProblematicCollectionViewCell.swift
override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
super.apply(layoutAttributes)
layoutIfNeeded()
}
Here is the origanl link : https://codedump.io/share/LXZwAOOMxafU/1/uicollectionviewcell---contents-do-not-animate-alongside-cell39s-contentview the answer is in the comments.

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.

Resources