Mobinius Technologies Pvt. Ltd.
May I help you?
May I help you?
Please leave a message with your contact details. Our representative will get in touch with you soon.

Animation with collection view

This blog will explain about creating animation with collectionView. Here in this example collectionView contains number of required custom cells. Each custom cell will have border Image & background Image. When we select particular cell, background image of selected cell is hidden & that border will be zoomed to Main view frame with some animation. While zooming it has to show its detail view behind it. Then remaining cells should zoom out.

Note : Here each cell is having different width & height(To achieve this we are using custom collection view layout).

To make it clear for the readers we have come up with the video which shows the final result.

Use collection view to represent data. A UICollectionViewLayout is a simple layout that allows the views to “Flow”, whether horizontally or vertically. It organizes items in a grid.

1

The interface definition is straight-forward as you can see below.

@interface MainDashboardCollectionLayout : UICollectionViewLayout
@end

We can give nice look to collection view in the layout itself. Their are number of configurable options available here.

Prepare layout will Tells the layout object to update the current layout.Subclasses can override it and use it to set up data structures or perform any initial computations needed to perform the layout.
In layoutAttributesForElementsInRect:, we setup an array of the visual objects, which contains their attributes.
LayoutAttributesForItemAtIndexPath: , we are setting frame for each item at indexpath.(originX & originY is currently hard coded. Width & height will be respect to image width & height).

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect
{
NSMutableArray* attributes = [NSMutableArray array];
for (NSInteger i=0 ; i < self.cellCount; i++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForItem:i inSection:0];
[attributes addObject:[self layoutAttributesForItemAtIndexPath:indexPath]];
}
return attributes;
}

– (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)path
{
UICollectionViewLayoutAttributes* attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:path];

UIImage *indexPathImage = [self.contentArr objectAtIndex:path.row];

CGFloat x = [self getXPositionForIndexPath:path];
CGFloat y = [self getYPositionForIndexPath:path];

attributes.frame = CGRectMake( x,y,indexPathImage.size.width,indexPathImage.size.height);

return attributes;
}

-(CGFloat)getXPositionForIndexPath:(NSIndexPath *)indexPath
{
NSArray *xPostionItemsArr = @[@123,@464,@17,@291,@611,@149,@501];
CGFloat xPos = 0;
if(indexPath.row < [xPostionItemsArr count])
xPos = [[xPostionItemsArr objectAtIndex:indexPath.row] floatValue];

return xPos;
}

-(CGFloat)getYPositionForIndexPath:(NSIndexPath *)indexPath
{
NSArray *yPostionItemsArr = @[@33,@40,@260,@222,@168,@431,@520];
CGFloat yPos = 0;
if(indexPath.row < [yPostionItemsArr count])
yPos = [[yPostionItemsArr objectAtIndex:indexPath.row] floatValue];

return yPos;
}
@end

We can set custom layout to collection view in 2 ways, Either programmatically or in nib. But here we are setting custom layout to collection view programmatically in viewDidLoad method, STMainDashboardViewController.

i.e. [self.collectionView setCollectionViewLayout:[[MainDashboardCollectionLayout alloc]init]];

shouldHighlightItemAtIndexPath & shouldSelectItemAtIndexPath delegates are implemented to hide the selected cell background image. This method will be called for each item at index path , if isCellTapped bool is YES only it will hide background image else not.

isCellTapped bool value we are setting in touch events methods (i.e. touchesBegan, touchesMoved,touchesEnded )of custom collection cell class.

2

- (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath
{
STMainDashboardCell *selectedCell=(STMainDashboardCell *)[self.collectionView cellForItemAtIndexPath:indexPath];

if(selectedCell.isCellTapped == NO){
return NO;
}else{
selectedCell.categoryImage.hidden = YES;
return YES;
}
}

– (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath;{
STMainDashboardCell *selectedCell=(STMainDashboardCell *)[self.collectionView cellForItemAtIndexPath:indexPath];

return selectedCell.isCellTapped;
}

MainViewController will be rootView controller in sample app, which holds all subviews in it.
To achieve requirement , we need to add collectionView & detailView to mainView

1. Create mainView
2. Add collectionView & detailView to mainView , detailView position should be behind the collectionView
3. After selecting cell, hide background image & zoom border image with animation.
4. Set collectionView alpha to 0 & show detail view.

Will see now how to achieve all above tasks for selected cell in collection view. All below implementation done in didSelectItemAtIndexPath:, collection view delegate method.

// ****************** step 1 ********************************************
If selected cell Controller is nill, instantiate View Controller from story board with its identifier. Here we are giving view controller identifier as controller class name itself. Set the selected controller view frame & add to main view, behind collection view by using insertSubview : belowSubview api .

if(nil == categoryController)
{
@try {
categoryController = [[self storyboard] instantiateViewControllerWithIdentifier:@”DetailedViewController”];
}
@catch (id anException) { //Exception will raise in case identifier is not set in storyboard.
if(nil == categoryController)
categoryController = [[UIViewController alloc] init];
}
}

[categoryController.view setFrame:self.view.frame];
// insert detail Controller as subview to mainViewController …
[self.mainViewController.view insertSubview:categoryController.view belowSubview:self.view];
// **************************************************************************

In step2, Hide background image of selected cell.

Here we are using CGAffineTransformScale to zoom selectedcell at center of view. So set selectedcell to center of view i.e . selectedCell.center = self.view.center, then transform the cell using CGAffineTransformScale.
Here we are using api:
CGAffineTransform CGAffineTransformScale(CGAffineTransform t,CGFloat sx, CGFloat sy)
I.e .
CGAffineTransform tr = CGAffineTransformScale(selectedCell.transform,2.5,2.5);

// ****************** step 2********************************************
// Animate selected cell & set frame for other cells..
STMainDashboardCell *selectedCell=(STMainDashboardCell *)[self.collectionView cellForItemAtIndexPath:indexPath];

[self.view bringSubviewToFront:selectedCell];

CGAffineTransform tr = CGAffineTransformScale(selectedCell.transform,2.5,2.5);
// **************************************************************************

In step 3, animation block in which we are setting frame for cells (setting selected cell frame to main view frame to zoom & remaining cell frame to move out, while selected cell is zooming with animation.). In sample we done with UIViewAnimationOptionBeginFromCurrentState animation.

And also can use different kind of animation for each cell to animate & set frame. You can use any of the following animation type in animation block I.e [UIView animateWithDuration:2.0 delay:0 options:0 animations:^{ }

1) Transition animation
2) Rotation animation

Example 1 : // UIViewAnimationTransitionCurlUp for each cell….
[UIView beginAnimations:nil context:nil];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:view cache:NO];
[UIView commitAnimations];

In this example we need to setAnimationCurve , setAnimationDuration & type of animation transition we need for cell transition.

Example 2 : // Rotate animation…
CABasicAnimation *theAnimation;

theAnimation=[CABasicAnimation animationWithKeyPath:@”transform.rotation”];
theAnimation.duration=0.1;
theAnimation.repeatCount=2;
theAnimation.autoreverses=YES;
theAnimation.fromValue=[NSNumber numberWithFloat:0.0];
theAnimation.toValue=[NSNumber numberWithFloat:((360*M_PI)/180)]; // M_PI/3
[view.layer addAnimation:theAnimation forKey:@”rotateLayer”];

In example2 , we are rotating cell. There is a repeatCount property on CAMediaTiming. repeatCount = 2 and Setting autoreverses = YES would cause the animation to grow, shrink, then grow and shrink again. The autoreverse happens for each repetition of the animation.

// ******************************** step 3******************************************
__block CGRect cellOriginalFrame;
__block CGRect newRect ;

[UIView animateWithDuration:2.0 delay:0 options:0 animations:^{

selectedCell.categoryImage.hidden = YES;
[self.view setBackgroundColor:[UIColor clearColor]];

for(UIView *view in self.collectionView.subviews){
if([view isKindOfClass:[STMainDashboardCell class]]){
if(view != selectedCell) {

[UIView animateWithDuration:.2
delay: 0.1
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{

cellOriginalFrame = view.frame;
CGRect cellFrame = view.frame;
CGRect collectionViewFrame = self.collectionView.frame;

if(view.frame.origin.x>selectedCell.frame.origin.x) {

if(view.frame.origin.y>selectedCell.frame.origin.y) {
cellFrame.origin.x = cellFrame.origin.x + collectionViewFrame.size.width;
cellFrame.origin.y = cellFrame.origin.y + collectionViewFrame.size.height;
}
else if(view.frame.origin.yselectedCell.frame.origin.y) {
cellFrame.origin.x = cellFrame.origin.x – collectionViewFrame.size.width;
cellFrame.origin.y = cellFrame.origin.y + collectionViewFrame.size.height;
}
else if(view.frame.origin.y cellFrame.origin.x = cellFrame.origin.x – collectionViewFrame.size.width;
cellFrame.origin.y = cellFrame.origin.y – collectionViewFrame.size.height;
}
else if(view.frame.origin.y == selectedCell.frame.origin.y && view != selectedCell) {
cellFrame.origin.x = cellFrame.origin.x – collectionViewFrame.size.width;
}
}
[view setFrame:cellFrame];
}
completion:^(BOOL finished){
}];
}
// **************************************************************************

In step4 we are calculating aspect ratio , set new frame for selected cell.

// ********************************** step 4****************************************
float hfactor = selectedCell.bounds.size.width / self.collectionView.frame.size.width;
float vfactor = selectedCell.bounds.size.height / self.collectionView.frame.size.height;

float factor = fmax(hfactor, vfactor);

// Divide the size by the greater of the vertical or horizontal shrinkage factor
float newWidth = selectedCell.bounds.size.width / factor;
float newHeight = selectedCell.bounds.size.height / factor;

// Then figure out if you need to offset it to center vertically or horizontally
float leftOffset = ( self.collectionView.frame.size.width – newWidth) / 2;
float topOffset = ( self.collectionView.frame.size.height – newHeight) / 2;

newRect = CGRectMake(leftOffset, topOffset, newWidth, newHeight);
}
}

[self.dashboardBgImage setAlpha:0.0];

//selectedCell.center = self.view.center;
selectedCell.frame = newRect;
selectedCell.transform = tr;
// **************************************************************************

If you don’t want to enlarge images smaller than the screenRect, make sure factor is greater than or equal to one (e.g. factor = fmax(factor, 1)).

In step 5 : It includes completion block, as soon as animation for selected cell compelted successfully,
set selectedCell.transform = CGAffineTransformIdentity, set view alpha value to 1 & reload collection view data.
// ********************************step5******************************************
} completion:^(BOOL finished) {

selectedCell.transform = CGAffineTransformIdentity;
self.view.transform = CGAffineTransformIdentity;

selectedCell.categoryImage.hidden = NO;
[self.dashboardBgImage setAlpha:1.0];
[self.view setAlpha:0.0];
[self.collectionView reloadData];
// **************************************************************************
}];
}

Conclusion :
This article introduced Animation for Collection View. Here we discussed the concepts of zooming the selected cell at a point using CGAffineTransformScale & show detail view. And the result is with a very nice animation which you can use to your next app!!

Provide your valuable feedback and revert us for any clarifications. See you again in next article…

Download the sample code from here: Collection View Animation