Im trying to create a cool animation with my collection view selection. Basically I have a collection view of photo cells displayed. What I want to happen is have the cell pop out of its location, scale and move to the center of the screen where the user will be prompted to confirm the selection.
Here is my code so far, but currently the animation takes the cells original frame location, so if I scroll it doesnt take into account that the frame position is no longer the same.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
PhotoCell *cell = (PhotoCell *)[collectionView cellForItemAtIndexPath:indexPath];
collectionView.allowsSelection = NO;
[self createAnimationWithCell:cell];
}
- (void)createAnimationWithCell:(PhotoCell *)cell {
UIImageView *selectedImage = [[UIImageView alloc] initWithFrame:cell.bounds];
selectedImage.center = cell.center;
selectedImage.image = cell.imageView.image;
[self.view addSubview:selectedImage];
[UIView animateWithDuration:2.5 animations:^{
selectedImage.center = self.view.center;
} completion:^(BOOL finished) {
[selectedImage removeFromSuperview];
self.collectionView.allowsSelection = YES;
}];
}
I solved it myself:
For those who are experiencing the same problem, we have to take into account how much the collection view has scrolled (offset) and use that information. I created a variable called collectionViewOffset and gave it an initial value of 0.0
then used:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
// getting the scroll offset
collectionViewOffset = scrollView.contentOffset.y;
NSLog(#"offset: %f", collectionViewOffset);
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
PhotoCell *cell = (PhotoCell *)[collectionView cellForItemAtIndexPath:indexPath];
//collectionView.allowsSelection = NO;
//collectionView.scrollEnabled = NO;
[cell.superview bringSubviewToFront:cell];
[UIView animateWithDuration:2.0 delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:.2 options:UIViewAnimationOptionCurveLinear animations:^{
cell.center = CGPointMake(self.view.vWidth/2, self.bannerView.vBottomEdge + collectionViewOffset + 40);
} completion:^(BOOL finished) {
}];
}
Related
Hi I am a beginner in iOS and in my project I have added a collection view programmatically and it was added successfully.
My requirement is when I click on UICollectionViewCell then it will be displayed full screen like below second image and when I click on close button image will go back to its actual position.
For this I have tried some code, but it's not working!
Please help me.
My code:-
#import "ViewController.h"
#interface ViewController ()
{
BOOL isFullScreen;
CGRect prevFrame;
UIImageView *dot;
NSArray * images;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
images = [[NSArray alloc]initWithObjects:#"1.png",#"2.png",#"3.png",#"4.png",#"5.png",#"6.png",#"7.png",#"8.png",#"9.png", nil];
isFullScreen = NO;
self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
_collectionView=[[UICollectionView alloc] initWithFrame:self.view.frame collectionViewLayout:layout];
[_collectionView setDataSource:self];
[_collectionView setDelegate:self];
_collectionView.backgroundColor = [UIColor whiteColor];
[_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:#"cellIdentifier"];
[self.view addSubview:_collectionView];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return 9;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
dot =[[UIImageView alloc] initWithFrame:CGRectMake(0,0,cell.frame.size.width,cell.frame.size.height)];
dot.image=[UIImage imageNamed:[images objectAtIndex:indexPath.row]];
[cell.contentView addSubview:dot];
return cell;
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
return CGSizeMake(100, 100);
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"cellIdentifier" forIndexPath:indexPath];
if (!isFullScreen) {
[UICollectionView animateWithDuration:0.5 delay:0 options:0 animations:^{
prevFrame = cell.frame;
[cell setFrame:[[UIScreen mainScreen] bounds]];
}completion:^(BOOL finished){
isFullScreen = TRUE;
}];
return;
}
else{
[UICollectionView animateWithDuration:0.5 delay:0 options:0 animations:^{
[cell setFrame:prevFrame];
}completion:^(BOOL finished){
isFullScreen = FALSE;
}];
return;
}
}
#end
Try
cell.framewill not give you the correct position of the cell on the screen, but the position within the content scrollview of the CollectionViewController
In order to find the correct frame, try
CGRect frameToAnimateTo = [self.navigationController.view convertRect:cell.frame fromView:self.collectionView];
To find the position of the cell view in the surrounding NavigationController.
As for the actual animation, it will be a bit more complicated than just transitioning views. Assuming you want to present the image in an own ViewController (which you don't necessarily have to, but your question indicates that you plan to...), you will have to implement a custom ViewController transition.
The easiest solution would be to develop a UIView with image view and button, that pops up from the collectionView and simply contains an UIImageView and an UIButton for closing.
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let vc = self.storyboard?.instantiateViewController(withIdentifier: "second") as! ViewController
let imagenew = UIImage(named: iosImages[indexPath.row])
print(imagenew!)
vc.img = imagenew as Any as! UIImage
navigationController?.pushViewController(vc, animated: true)
}
Send the image value to the next view controller and store that in the UIImage variable, then passed that value to the UIImageView for display.
i make an application that conatin UICollectionview with CustumCell and each Cell Contain images i want to make when any image selected then it was zoom in view and when zoom view touch
then collectionview was Shown like as a URBMediaFocusViewController Libraray
link of library is here URBMediaFocusViewController
i know it was asked many times but please give me solution.
It's not very elegant, but this is how I do it. Basically get the frame location and size of your source UICollectionView Cell, the frame and location of where you want it to appear (in this case I fill the view), then animate between the two sizes. Hope this helps.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[collectionView selectItemAtIndexPath:indexPath animated:YES scrollPosition:UICollectionViewScrollPositionCenteredHorizontally];
[self zoomToSelectedImage:indexPath];
}
-(void)zoomToSelectedImage:(NSIndexPath *)indexPath
{
UIImageView *zoomImage = [[UIImageView alloc] initWithImage:[self.myPictures objectAtIndex:indexPath.row]];
zoomImage.contentMode = UIViewContentModeScaleAspectFit;
CGRect zoomFrameTo = CGRectMake(0,0, self.view.frame.size.width,self.view.frame.size.height);
UICollectionView *cv = (UICollectionView *)[self.view viewWithTag:66]; // Change to whatever the tag value of your collectionView is
cv.hidden = TRUE;
UICollectionViewCell *cellToZoom =(UICollectionViewCell *)[cv cellForItemAtIndexPath:indexPath];
CGRect zoomFrameFrom = cellToZoom.frame;
[self.view addSubview:zoomImage];
zoomImage.frame = zoomFrameFrom;
zoomImage.alpha = 0.2;
[UIView animateWithDuration:0.2 animations:
^{
zoomImage.frame = zoomFrameTo;
zoomImage.alpha = 1;
} completion:nil];
I would like to resize my tableView cell when the user selects a row, the cell becomes smaller then larger again. This is what I have tried so far:
#pragma mark UITableView Delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
// My animation
cell.contentView.transform = CGAffineTransformMakeScale(0.95,0.95);
cell.contentView.alpha = 1.f;
[UIView beginAnimations:#"button" context:nil];
[UIView setAnimationDuration:0.2];
cell.contentView.transform = CGAffineTransformMakeScale(1,1);
cell.contentView.alpha = 1.0f;
[UIView commitAnimations];
}
This is my tableView data source:
#pragma mark UITableView Datasource
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Set up cell
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.backgroundColor = [UIColor clearColor];
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue" size:21];
cell.textLabel.textColor = [UIColor whiteColor];
cell.textLabel.highlightedTextColor = [UIColor lightGrayColor];
cell.selectedBackgroundView = [[UIView alloc] init];
}
// Images in my cell
NSArray *images = #[#"Songs", #"Albums", #"Artists", #"Playlists"];
UIImageView *cellImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:images[indexPath.row]]];
cellImage.frame = CGRectMake(0, 0, 90, 90);
[cell addSubview:cellImage];
return cell;
}
But this does not work. The image in the cell simply stays the same size. Any ideas? Thanks.
I seriously advise going with a UICollectionView for something like this. With it, you only have to call performBatchUpdates and you can put any frame setting inside of it's block. It's practically magic!
I don't know if you can or should do what you ask about, but if you can it would probably be with a custom UITableViewCell. But, you might be able to fake it with a custom cell, maybe with a UIView that holds all the cell's contents. The UIView would animate inside the cell, and if you are not showing separators on the table it could look like the cell itself is animating. So basically you're hiding the actual cell, and using a UIView in the cell to simulate animating the cell. Maybe like this:
[UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.customCell.frame = CGRectMake(110, 20, 100, 20);
} completion:^(BOOL finished) {
[UIView animateWithDuration:SLIDE_TIME delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.customCell.frame = CGRectMake(0, 0, 320, 60);
} completion:^(BOOL finished) {
}];
}];
I want to animate my collectionview cell so that when I touch it, a mapview slides out from underneath it and basically expands into the space, by pushing the cell underneath it down a little bit. I tried using this: UICollectionView: Animate cell size change on selection, but was unable to get it to work properly.
Here what I tried.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
[((FeedCell *)[collectionView cellForItemAtIndexPath:indexPath]) setIsSelected:YES];
[collectionView.collectionViewLayout invalidateLayout];
__weak FeedCell *cell = (FeedCell *)[self.photoCollectionView cellForItemAtIndexPath:indexPath]; // Avoid retain cycles
void (^animateChangeWidth)() = ^()
{
CGRect frame = cell.frame;
frame.size = CGSizeMake(frame.size.width, 420);
cell.frame = frame;
};
// Animate
[UIView transitionWithView:[collectionView cellForItemAtIndexPath:indexPath] duration:0.5f options: UIViewAnimationOptionCurveLinear animations:animateChangeWidth completion:nil];
}
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
if(((FeedCell *)[self.photoCollectionView cellForItemAtIndexPath:indexPath]).isSelected == YES){
return CGSizeMake(320, 420);
}
return CGSizeMake(320, 320);
}
I have a custom CollectionView cell and it has a property for isSelected. I'm not sure what I should do for the xib of the cell (whether to put the map view in there, have the CGSize be the selected size or deselected size, etc.) Any help would really be appreciated!
I am trying to do the same thing as you and found your question in my search. It appears that you have a pretty good solution (at least in my inexperienced opinion). What isn't working for you? I got it to do what I wanted by copying your code almost verbatim. I changed a few things, but didn't test the code before making the changes. Here is what I have that works for me in my didSelectItemAtIndexPath method:
__weak MyCell *cell = (MyCell*)[collectionView cellForItemAtIndexPath:indexPath];
[cell setSelected:YES];
[collectionView.collectionViewLayout invalidateLayout];
void (^animateChangeWidth)() = ^()
{
CGRect frame = cell.frame;
frame.size = CGSizeMake(frame.size.width, 340.0f);
cell.frame = frame;
};
// Animate
[UIView transitionWithView:cell duration:0.5f options: UIViewAnimationOptionCurveEaseInOut animations:animateChangeWidth completion:nil];
I also have overridden collectionView:layout:sizeForItemAtIndexPath so I assume that is working for you as well.
Sorry I can't be more specific. It would help if you said what about it wasn't working.
How can I achieve the animation where a UICollectionViewCell with flip and grow to show modal view on tap?
Here is what I used in another project and it was working well :
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
if (cell.selected) {
[collectionView deselectItemAtIndexPath:indexPath animated:YES];
[UIView transitionWithView:cell
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[cell setFrame:self.selectedCellDefaultFrame];
cell.transform = self.selectedCellDefaultTransform;
}
completion:^(BOOL finished) {
self.selectedCellDefaultFrame = CGRectZero;
[collectionView reloadItemsAtIndexPaths:#[indexPath]];
}];
return NO;
}
else {
return YES;
}
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
[cell.superview bringSubviewToFront:cell];
self.selectedCellDefaultFrame = cell.frame;
self.selectedCellDefaultTransform = cell.transform;
[UIView transitionWithView:cell
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromRight
animations:^{
[cell setFrame:collectionView.bounds];
cell.transform = CGAffineTransformMakeRotation(0.0);
}
completion:^(BOOL finished) {}];
}
Different things here :
The bringSubviewToFront: message call is used to prevent the cell to animate behind the other cells
We use two properties declared in the controller : selectedCellDefaultFrameand selectedCellDefaultTransform to save the default state of the cell and reinitialize it when deselecting
When deselecting, we call the reloadItemsAtIndexPaths: method of UICollectionView to be sure that the reset of the position is totally complete
Let me know if you have any trouble with this.
Good luck,
I haven't tried the grow animation, but I think I can help with the UICollectionViewCell flip animation.
Try:
UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
[UIView animateWithDuration:1.0
delay:0
options:(UIViewAnimationOptionAllowUserInteraction)
animations:^
{
NSLog(#"starting animation");
[UIView transitionFromView:cell.contentView
toView:newView
duration:.5
options:UIViewAnimationOptionTransitionFlipFromRight
completion:nil];
}
completion:^(BOOL finished)
{
NSLog(#"animation end");
}
];
Hope that helps!