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.
Related
Guys I need your help ... I created a custom control segment through an UICollectionView ..
CustomView.m
I have 5 cells that contain a label with the title of the cell
To get the cell width by the width of the UILabel I implemented the sizeForItemAtIndexPath method in this way:
-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
CGSize size = [[[self titleSection] objectAtIndex:indexPath.item] sizeWithAttributes:nil];
return CGSizeMake(size.width +35 , self.frame.size.height);
}
I also created a UIView that has the cursor function that indicates which cell has been selected.
To animate the cursor (UIView) I implemented this way:
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:indexPath.item inSection:0];
[collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
UDPassData *data = [UDPassData sharedInstance];
[data.sectionContentCollection scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionNone animated:YES];
if (indexPath == newIndexPath) {
[collectionView scrollToItemAtIndexPath:indexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally animated:YES];
}
UICollectionViewLayoutAttributes *attributes = [collectionView layoutAttributesForItemAtIndexPath:newIndexPath];
CGRect cellFrameInSuperview = [collectionView convertRect:attributes.frame toView:collectionView];
data.index = cellFrameInSuperview;
[UIView animateWithDuration:.4 delay:0 usingSpringWithDamping:1 initialSpringVelocity:1 options:UIViewAnimationOptionCurveEaseInOut animations:^{
_horizontalBar.frame = CGRectMake(cellFrameInSuperview.origin.x, _horizontalBar.frame.origin.y, cellFrameInSuperview.size.width , 3);
} completion:nil];
}
UICollectionViewController.m
now in another ViewController i have another UICollectionView with horizontal scrolling that shares the index path with the segment control so that I can control the scrolling of the collectionView even with the custom segment control .. To here everything works and I managed to get everything but I just have a problem ..
The segment control slider does not move when uicollection view scrolls ... In short, if the collectionView is in cell two, the custom segment control cursor should move to the second cell in the segment control I created .. I hope to to be able to explain
EDIT : What I'm trying to get is this I've seen from the Youtube application. The top menu ...
I'm doing this with 2 collectionView.
the first collectionView is the menu (built into a UIView custom class)
the second collectionView is browsing between pages and is located in an external UIViewController
Make sure to reload collectionView Data Source in order to fresh it.
[self.collection1 performBatchUpdates:^{
[collectionView reloadData]
} completion:nil];
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) {
}];
}
I am trying to animate a tableview on a view that uses autolayout.
I am able to animate the tableview fine but for some reason there is a unwanted sideways animation when doing so.
The first animation closes the top tableview works fine. However the second animation that extends the bottom tableview is the one that has the sideways movement. Here is my code:
[self.dataSelectionTable layoutIfNeeded];
[self.comparatorSelectionTable layoutIfNeeded];
[UIView animateWithDuration:0.5 animations:^{
self.dataSelectionTableHeight.constant = 44;
[self.view layoutIfNeeded]; and then captures all of the frame changes
} completion:^(BOOL finished){
[UIView animateWithDuration:0.5 animations:^{
self.comparatorSelectionTableHeight.constant = 200;
[self.view layoutIfNeeded];
}];
}];
I have tried changing the animation type but that does not seem to work.
Here is a link to a gif that shows the unwanted sideways animation: http://makeagif.com/YubmP2
Edit
Here is the code for populating the tableviews:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
cell.textLabel.numberOfLines = 0;
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:13.0];
}
if (tableView == self.dataSelectionTable) {
cell.textLabel.text = self.dataSelectionTitles[indexPath.row];
}
else {
cell.textLabel.text = [self.comparatorList[indexPath.row] name];
}
return cell;
}
I tried to duplicate your problem, but got slightly different results. Instead of a sideways movement, I got a downward movement of the label within the cell (but only the first time I did the animation).
I noticed that if I set the table view's height constraint's constant value to 0 in viewDidLoad, cellForRowAtIndexPath was not called until I did the expansion, so I'm guessing that some of the laying out of views of the table view wasn't happening until then.
I fixed the problem by setting the alpha value of the table view to 0 in IB, and set its height to 400 (the value I wanted after expansion). Then in viewDidAppear, I did this,
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
self.heightCon.constant = 0;
self.tableView.alpha = 1;
}
This caused the table's data source methods to run right away, but with the table view not visible. Now when I animated the expansion, I didn't get any movement of the label within the cell.
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];
My question in short: how can this effect on UICollectionView be achieved?
I have a collectionview with a custom layout that is similar to a gridlayout. Now when I enter the collectionview controller I want the cells to have a nice animation.
I know I can implement - initialLayoutAttributesForAppearingItemAtIndexPath: etc and call performBatchUpdates on the collectionview. Now when I do this all the animations are executed in parallel (like calling UIView animate). In a lot of apps I see effects where this isn't done in paralell like the philips hue app on iPhone, the effect can be seen in the movie posted at the top. One thing I could think if is that instead of inserting all the objects here the rows are added separatly, so for instance all rows are looped and dispatched after a certain interval next from each other.
Anyway if someone could hint me what the best approach is for achieving this effect or knows about a sample that does something similar I would be very grateful.
Here's one way of doing it: (I felt kinda dirty after writing this.. but it works)
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"cell" forIndexPath:indexPath];
cell.myPic.image = [UIImage imageNamed:[NSString stringWithFormat:#"%d.jpg",indexPath.row]];
CGRect frame = cell.myPic.frame;
frame.origin.y = cell.myPic.frame.origin.y + 40;
cell.myPic.frame = frame;
cell.myPic.alpha = 0;
[cells addObject:cell];
return cell;
}
- (IBAction)Run:(UIButton *)sender
{
for (int i=0; i<[cells count]; i++)
{
myCell *cell = [cells objectAtIndex:i];
[UIView animateWithDuration:0.15 animations:^() {
CGRect frame = cell.myPic.frame;
frame.size.width = 80;
frame.origin.y = cell.myPic.frame.origin.y - 40;
cell.myPic.frame = frame;
cell.myPic.alpha = 1;
}completion:^(BOOL finished){}];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.05]];
}
}