Adrià Carro
Adrià Carro

Reputation: 717

UICollectionView into UICollectionViewCell

I need to add UICollectionView into UICollectionViewCell. It seems easy but I don't get it.

I don't get to know where I have to initialize UICollectionView for each UICollectionViewCell and where to program UICollectionViewDataSource and UICollectionViewDelegate of each UICollectionView.

The result would be a collection of products (first collectionview where each cell is a product) and a collection of images for each product like image gallery (second collection view where each cell is an image). It's the same as Zara app.

First collection view looks like this and have only vertical scroll.

enter image description here

When you select a product, cells change their size to full screen size and the collection view change vertical scrolling to horizontal scrolling. Now vertical scrolling is for the second collection view, the image gallery.



Second collection view looks like this

enter image description here



In storyboard I have UICollectionViewController with UICollectionViewDataSource, UICollectionViewDelegate and UICollectionViewDelegateFlowLayout implementations.

ProductsCollectionViewController.h

@interface ProductsCollectionViewController : UICollectionViewController <UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout> {
    NSMutableArray *products;
}

ProductsCollectionViewController.m

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return products.count;
}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *identifier = @"ProductCell";

    ProductCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    Product *product = [products objectAtIndex:indexPath.row];
    [cell setProduct:product];

    return cell;
}

Product is a main NSObject that have some information and also an array of images.

Product.h

@interface Product : NSObject

@property NSInteger categoryID;
@property NSInteger productID;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) NSArray *images;



I think that what I have to do is create new UICollectionView programatically in each ProductCollectionViewCell with the array of images of the product but ProductCollectionViewCell don't recognize UICollectionViewDataSource and UICollectionViewDelegate and their implementation.

Upvotes: 2

Views: 2997

Answers (2)

pnovales
pnovales

Reputation: 27

Using StoryBoard is possible too.

Inspired in Ash Furrow's article

The main trick is in "willDisplayCell" method. Just make sure you are using the correct UICollectionViewCell class.

-(void)collectionView:(UICollectionView *)collectionView willDisplayCell:(PNCollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{

    if ([cell isKindOfClass:[PNCollectionViewCell class]]) {

        [cell setCollectionViewDataSourceDelegate:self indexPath:indexPath];
        NSInteger index = cell.collectionView.indexPath.row;

        CGFloat horizontalOffset = [self.contentOffsetDictionary[[@(index) stringValue]] floatValue];
        [cell.collectionView setContentOffset:CGPointMake(horizontalOffset, 0)];
    }

}

For more details you can see my sample on: https://github.com/pnovales/UICollectionViewInUICollectionViewCell

Upvotes: 0

Irfanlone
Irfanlone

Reputation: 564

Lets start by having a mainCollectionView. Then on each cell of this collection create and initialize a new UICollectionView and right place to do that is in this following delegate of UICollectionView

func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath)

e.g I initialize the MainCollectionViewCell here and then MainCollectionViewCell handles the logic to create a new UICollectionView

guard let collectionViewCell = cell as? MainCollectionViewCell else { return }

    collectionViewCell.delegate = self

    let dataProvider = ChildCollectionViewDataSource()
    dataProvider.data = data[indexPath.row] as NSArray

    let delegate = ChildCollectionViewDelegate()

    collectionViewCell.initializeCollectionViewWithDataSource(dataProvider, delegate: delegate, forRow: indexPath.row)

    collectionViewCell.collectionViewOffset = storedOffsets[indexPath.row] ?? 0

Here is the initializer on MainCollectionViewCell that creates a new UICollectionView

func initializeCollectionViewWithDataSource<D: protocol<UICollectionViewDataSource>,E: protocol<UICollectionViewDelegate>>(dataSource: D, delegate :E, forRow row: Int) {

    self.collectionViewDataSource = dataSource

    self.collectionViewDelegate = delegate

    let flowLayout = UICollectionViewFlowLayout()
    flowLayout.scrollDirection = .Horizontal

    let collectionView = UICollectionView(frame: self.bounds, collectionViewLayout: flowLayout)
    collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: reuseChildCollectionViewCellIdentifier)
    collectionView.backgroundColor = UIColor.whiteColor()
    collectionView.dataSource = self.collectionViewDataSource
    collectionView.delegate = self.collectionViewDelegate
    collectionView.tag = row

    self.addSubview(collectionView)

    self.collectionView = collectionView

    collectionView.reloadData()
}

Hope that helps !!

I did an example for this and put in on github. It demonstrates the use UICollectionView inside a UICollectionViewCell.

https://github.com/irfanlone/Collection-View-in-a-collection-view-cell

Upvotes: 2

Related Questions