UICollectionView in a UICollectionViewCell

There's an article that Ash Furrow wrote that explains how to put an UICollectionView inside an UITableViewCell. It's basically the same idea when using it inside an UICollectionViewCell.


Easiest solution for collectionview inside collectionview using storyboard and Swift 5

Please refer this link for nested collectionview example

import UIKit
class ParentViewController:UIViewController,UICollectionViewDataSource,UICollectionViewDelegate {
//MARK: Declare variable

//MARK: Decalare outlet
@IBOutlet weak var outerCollectionView: UICollectionView!
@IBOutlet weak var pageControl: UIPageControl!
let outerCount = 4

//MARK: Decalare life cycle methods
override func viewDidLoad() {
    super.viewDidLoad()
    pageControl.numberOfPages = outerCount
    
}
//MARK: Collection View delegate methods
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return outerCount
}
//MARK: Collection View datasource methods
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "OuterCell", for: indexPath) as! OuterCollectionViewCell
    cell.contentView.backgroundColor = .none
    return cell
    
}
//MARK:- For Display the page number in page controll of collection view Cell
func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let visibleRect = CGRect(origin: self.outerCollectionView.contentOffset, size: self.outerCollectionView.bounds.size)
    let visiblePoint = CGPoint(x: visibleRect.midX, y: visibleRect.midY)
    if let visibleIndexPath = self.outerCollectionView.indexPathForItem(at: visiblePoint) {
        self.pageControl.currentPage = visibleIndexPath.row
    }
}
}
class OuterCollectionViewCell: UICollectionViewCell ,UICollectionViewDataSource,UICollectionViewDelegate {

@IBOutlet weak var InnerCollectionView: UICollectionView!

override func awakeFromNib() {
    super.awakeFromNib()
    InnerCollectionView.delegate = self
    InnerCollectionView.dataSource = self
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    6
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InnerCell", for: indexPath) as! InnerCollectionViewCell
    cell.contentView.backgroundColor = .green
    return cell
}


}
class InnerCollectionViewCell: UICollectionViewCell{


}

Everything is done programatically. No storyboards.

I added a UICollectionView inside my UICollectionViewCell. I also show how to add again a UICollectionViewCell inside the created UICollectionView to have this result

enter image description here

import UIKit

class CategoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    private let cellId = "cell"

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    let appsCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        return collectionView
    }()

    func setupViews() {
        backgroundColor = .blue

        addSubview(appsCollectionView)

        appsCollectionView.delegate = self
        appsCollectionView.dataSource = self
        appsCollectionView.register(AppCell.self, forCellWithReuseIdentifier: cellId)

        addConstrainstWithFormat("H:|-8-[v0]-8-|", views: appsCollectionView)
        addConstrainstWithFormat("V:|[v0]|", views: appsCollectionView)

    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
        return cell
    }
}

class AppCell: UICollectionViewCell {
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    func setupViews(){
        backgroundColor = .red
    }
}

My UICollectionViewController

import UIKit

class FeaturedAppsController: UICollectionViewController, UICollectionViewDelegateFlowLayout {

    let cellId = "cell"

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        collectionView?.backgroundColor = .white
        collectionView?.register(CategoryCell.self, forCellWithReuseIdentifier: cellId)
    }

    override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 3
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(view.frame.width, 150)
    }

}

The whole explanation can be found and was developed by "Let´s build that app": https://www.youtube.com/watch?v=Ko9oNhlTwH0&list=PL0dzCUj1L5JEXct3-OV6itP7Kz3tRDmma


This is too late for this answer but it might help others. This is an example of UICollectionView inside a UICollectionViewCell.

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