According to Apple's documentation (and touted at WWDC 2012), it is possible to set the layout on UICollectionView
dynamically and even animate the changes:
You normally specify a layout object when creating a collection view but you can also change the layout of a collection view dynamically. The layout object is stored in the collectionViewLayout property. Setting this property directly updates the layout immediately, without animating the changes. If you want to animate the changes, you must call the setCollectionViewLayout:animated: method instead.
However, in practice, I've found that UICollectionView
makes inexplicable and even invalid changes to the contentOffset
, causing cells to move incorrectly, making the feature virtually unusable. To illustrate the problem, I put together the following sample code that can be attached to a default collection view controller dropped into a storyboard:
#import <UIKit/UIKit.h> @interface MyCollectionViewController : UICollectionViewController @end @implementation MyCollectionViewController - (void)viewDidLoad { [super viewDidLoad]; [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"CELL"]; self.collectionView.collectionViewLayout = [[UICollectionViewFlowLayout alloc] init]; } - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return 1; } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { UICollectionViewCell *cell = [self.collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath]; cell.backgroundColor = [UIColor whiteColor]; return cell; } - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"contentOffset=(%f, %f)", self.collectionView.contentOffset.x, self.collectionView.contentOffset.y); [self.collectionView setCollectionViewLayout:[[UICollectionViewFlowLayout alloc] init] animated:YES]; NSLog(@"contentOffset=(%f, %f)", self.collectionView.contentOffset.x, self.collectionView.contentOffset.y); } @end
The controller sets a default UICollectionViewFlowLayout
in viewDidLoad
and displays a single cell on-screen. When the cells is selected, the controller creates another default UICollectionViewFlowLayout
and sets it on the collection view with the animated:YES
flag. The expected behavior is that the cell does not move. The actual behavior, however, is that the cell scroll off-screen, at which point it is not even possible to scroll the cell back on-screen.
Looking at the console log reveals that the contentOffset has inexplicably changed (in my project, from (0, 0) to (0, 205)). I posted a solution for the solution for the non-animated case (i.e. animated:NO
), but since I need animation, I'm very interested to know if anyone has a solution or workaround for the animated case.
As a side-note, I've tested custom layouts and get the same behavior.
Overview. A flow layout is a type of collection view layout. Items in the collection view flow from one row or column (depending on the scrolling direction) to the next, with each row containing as many cells as will fit. Cells can be the same sizes or different sizes.
The collection view presents items onscreen using a cell, which is an instance of the UICollectionViewCell class that your data source configures and provides. In addition to its cells, a collection view can present data using other types of views.
Tableiw is a simple list, which displays single-dimensional rows of data. It's smooth because of cell reuse and other magic. 2. UICollectionView is the model for displaying multidimensional data .
UICollectionViewLayout
contains the overridable method targetContentOffsetForProposedContentOffset:
which allows you to provide the proper content offset during a change of layout, and this will animate correctly. This is available in iOS 7.0 and above
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With