How can I use UICollectionViewLayout data for invisible cells?

I would like to get all the data from the data source — for both visible and invisible cells — to calculate the attributes for the visible cells. collectionView:cellForItemAtIndexPath: does not work because it returns nil for invisible cells. As stated in the UICollectionView API :

Return value

The cell object in the corresponding index path, or nil if the cell is not visible, or indexPath is out of range.

Any ideas on how I can extract the underlying data without violating MVC restrictions (e.g. keeping a link to the data in the layout)?

+6
source share
1 answer

The main problem that I am facing is that I need information from a basic data source to configure the attributes of visible and invisible cells, as well as additional representations. The UICollectionViewDelegate protocol requires cells to be deleted after the layout attributes are already set, although the implementation class (usually the UICollectionViewController has access to the data source).

collection programming hints> so that the delegate object can be extended to provide additional information. Using UICollectionViewDelegateFlowLayout as a reference , I created a new protocol that declares methods for the data I need. My subclass of UICollectionViewController then complied with this protocol, implementing these methods without any layout operations (for example, to delete view objects).

My protocol looks something like this:

 @protocol MyCollectionViewDelegateLayout <UICollectionViewDelegate> - (CGSize)sizeForCellAtIndexPath:(NSIndexPath *)indexPath; - (CGSize)sizeForHeaderAtIndexPath:(NSIndexPath *)indexPath; @end 

My collection view controller has the following structure:

 @interface MyCollectionViewController : UICollectionViewController <MyCollectionViewDelegateLayout> ... @end @implementation MyCollectionViewController ... - (CGSize)sizeForCellAtIndexPath:(NSIndexPath *)indexPath { // Make calculations based on data at index path. return CGSizeMake(width, height); } - (CGSize)sizeForHeaderAtIndexPath:(NSIndexPath *)indexPath; { // Make calculations based on data at index path. return CGSizeMake(width, height); } 

Inside the prepareLayout method in my subclass of UICollectionViewLayout I call these methods to pre-compute the required attributes:

 @implementation MyCollectionViewLayout ... - (void)prepareLayout { ... // Iterate over sections and rows... id dataSource = self.collectionView.dataSource; if ([dataSource respondsToSelector:@selector(sizeForCellAtIndexPath:)]) { CGSize size = [dataSource sizeForCellAtIndexPath:indexPath]; } else { // Use default values or calculate size another way } ... } ... 

Using an extended data source protocol allows the code to support separation of concerns between MVCs. Here, the layout class still doesn't know anything about the underlying data, but can use it to define attributes. In contrast, the controller class does not post anything; instead, it provides only size hints based on the underlying data.

+3
source

All Articles