UICollectionVIew: Animate cells as they scroll in
I would like items in my UICollectionView
to animate in to view as the user scrolls through the list (I am using a subclass of UICollectionViewFlowLayout
).
I specify the position in the Layout Manager, what I would like to be able to do is to also specify an initial transform and have that applied in an animation at the correct time (when the cell first appears on screen). To see the effect I mean, check out the Google Plus app on iOS. Ideally a different transform depending on the location of the cell.
I can't seem to find a way to find out when a cell is displayed (no equivalent of willDisplayCell
as there is on UITableView
) or any pointers on where to go for this.
Any suggestions?
You can just about make out the animation in Google Plus in this screen shot:
Also, take a look at iPhoto on the iPad. I don't know if they're using a UIcollectionView (probably not, as it worked on iOS5) but this is the sort if effect I'm looking for, the photos appear to fly in from the right.
You can achieve this effect independently of having a custom layout.
The animation code should go inside collectionView:cellForItemAtIndexPath:
When a cell is dequeued, its frame
will be set to what is specified in your layout. You can store it in a temporary variable as the final frame
for the cell. You can then set the cell.frame
to a initial position outside the screen, and then animate towards the desired final position. Something along the lines of:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionView *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
CGRect finalCellFrame = cell.frame;
//check the scrolling direction to verify from which side of the screen the cell should come.
CGPoint translation = [collectionView.panGestureRecognizer translationInView:collectionView.superview];
if (translation.x > 0) {
cell.frame = CGRectMake(finalCellFrame.origin.x - 1000, - 500.0f, 0, 0);
} else {
cell.frame = CGRectMake(finalCellFrame.origin.x + 1000, - 500.0f, 0, 0);
}
[UIView animateWithDuration:0.5f animations:^(void){
cell.frame = finalCellFrame;
}];
return cell;
}
The code above will animate cells on a horizontal UICollectionView
, coming from the top of the screen, and from either side, depending on the scrolling direction. You could also check the current indexPath
to have cells animating from different positions on more complicated layouts, as well as animate other properties along with the frame, or apply a transform.
You need to override initialLayoutAttributesForAppearingItemAtIndexPath:
in your collection view layout. Here you can set any attribute on the layout attributes item (including the transform) which will be animated to the actual attributes after the cell has appeared.
If the standard layout attributes object doesn't give you enough options, you can subclass it, add extra attributes, and override applyLayoutAttributes:
on your cell to pick up the extra properties.
This will only work when you are adding cells to the collection view.
To have transforms applied to cells as you scroll down the collection view, I'd look at applying them either directly to the cell (at cellForItem
...) or in the layout attributes, perhaps a property called initialTransform
. When applying the layout attributes to the cell, you'd check the initialTransform
, apply it, then set it to identity, then trigger an animation to go to the identity transform, so it would only be applied when the cell was first scrolled onto the screen. I haven't implemented anything like this, it's just a guess as to how I would do it.
As Marc mentioned in a comment, that he ended up using a scroll view I want to show how to do it with a standard table view. It is not the same effect as seen in google+ but could be adapted easily.
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
static CGFloat duration = .5;
static NSUInteger xOffset = 50;
static NSUInteger yOffset = 200;
if(scrollDirection == STAScrollDirectionDown && lastAnimatedIndex < indexPath.row)
{
cell.frame = CGRectMake(cell.frame.origin.x - xOffset, cell.frame.origin.y+yOffset, cell.frame.size.width, cell.frame.size.height);
[UIView animateWithDuration:duration
animations:^{
cell.frame = CGRectMake(cell.frame.origin.x + xOffset, cell.frame.origin.y - yOffset, cell.frame.size.width, cell.frame.size.height);
} completion:^(BOOL finished) {
lastAnimatedIndex = indexPath.row;
}];
}
}
Just before the cell is being displayed we assign an offset (and possibly a rotation) to each cell and than we animate it back to the previous settings.
a little more exciting example:
-(void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
CATransform3D rotation = CATransform3DMakeRotation( (90.0*M_PI)/180, .0, 0.5, 0.5);
cell.contentView.alpha = 0.8;
cell.contentView.layer.transform = rotation;
cell.contentView.layer.anchorPoint = CGPointMake(0, 0.5);
[UIView animateWithDuration:.5
animations:^{
cell.contentView.layer.transform = CATransform3DIdentity;
cell.contentView.alpha = 1;
cell.contentView.layer.shadowOffset = CGSizeMake(0, 0);
} completion:^(BOOL finished) {
}];
}
链接地址: http://www.djcxy.com/p/84162.html