19

I am trying to create an effect where I change the layout of my UICollectionView while changing the frame size

Initially the collectionView layout presents a "thumbnail" gallery style full screen.

After resizing the frame to a thin strip - I would like to present a "film strip" style layout

both layouts independently work fine and as expected.

I tried code similar to this:

[UIView animateWithDuration:1
                          delay:0.0
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         self.collectionview.frame = newFrame; // animate the frame size


                     }
                     completion:^(BOOL finished) {
                        [self.collectionView.collectionViewLayout invalidateLayout];

    [self.collectionView setCollectionViewLayout:filmstriplayout animated:YES];    // now set the new layout
                     }];

But it is looking very choppy and not resizing as expected.

Is there a way where I could change the collectionview layout and the frame size simultaneously while animating the change?

Avner Barr
  • 13,049
  • 14
  • 82
  • 152
  • Did you ever get a good solution? `performBatchUpdates:withCompletion:` is good, but doesn't help with combining an animated `frame` or `contentOffset` change. I want to get this for smoothly animating zoom bounce back where my layout and `contentOffset` dependent on zoom. – Benjohn Aug 02 '15 at 10:31

3 Answers3

20

I don't have a specific answer, but a few suggestions to consider.

UICollectionView doesn't always handle switching layout instances gracefully. Here is a good discussion of the problem and some workarounds.

But what I’ve actually done in practice that worked for me was to implement both layouts in a single layout object that knows how to toggle between layout modes. I found that switching layout modes in a batch update block was less problematic than using setCollectionViewLayout with two different layout instances:

[self.collectionView performBatchUpdates:^{
    MyLayout *layout = (MyLayout *)self.collectionView.collectionViewLayout;
    layout.mode = otherLayoutMode;
} completion:nil];
Constantino Tsarouhas
  • 6,736
  • 6
  • 43
  • 54
Timothy Moose
  • 9,773
  • 3
  • 31
  • 44
20

First set the grid item size like gridItemSize = CGSizeMake(98, 98); then perform the batch action of UICollectionView. The items in collection view change their sizes with animation. :)

- (CGSize)collectionView:(UICollectionView *)collectionView
                  layout:(UICollectionViewLayout*)collectionViewLayout
  sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
   return CGSizeMake(gridItemSize.width, gridItemSize.height);
}

[self.collectionview performBatchUpdates:^{
    [self.collectionview.collectionViewLayout invalidateLayout];
    [self.collectionview setCollectionViewLayout:self.collectionview.collectionViewLayout animated:YES];
} completion:^(BOOL finished) {    
}];
gklka
  • 2,233
  • 1
  • 23
  • 50
Zulqarnain
  • 1,417
  • 1
  • 19
  • 25
  • 2
    This is handy stuff, but **what about that animated frame change** occurring at the same time? Equivalently, I think, a `contentOffset` change? I also need both to happen at once. – Benjohn Aug 02 '15 at 10:25
  • In my use case, my flowLayout needs to be different when it's being scrolled and when it's static. What I do is: (1st) set a flag in the layout and use the code above to invalidate the layout; (2nd) scrollToIndexPath animated using the default collectionViewMethod; (3rd) reset the layout flag and use the above code again to animate it back to the original state. I couldn't achieve the desired results by animating them at the same time, so I just queued the animations. – marcelosalloum Oct 23 '19 at 12:49
  • `[self.collectionview.collectionViewLayout invalidateLayout];` is odd here, it leads to bugs in animation. – surfrider May 22 '20 at 13:14
-3

Here is the simple trick whenever you are updating the CollectionView use this:

[self.collectionView removeFromSuperview]; //First remove the Collection View

//Relocate the view with layouts
UICollectionViewFlowLayout *layout=[[UICollectionViewFlowLayout alloc] init];
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
layout.minimumInteritemSpacing = 10;
layout.minimumLineSpacing = 10;

 self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.width,100) collectionViewLayout:layout];
[self.collectionView setDataSource:self];
[self.collectionView setDelegate:self];
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
[self.collectionView reloadData];

[self.view addSubview:self.collectionView];
Shivam Singh
  • 83
  • 1
  • 3