Creating UICollectionView programmatically (outside of UIViewController) - ios

I would like to create a subclass ofimport UIKit
class AlbumPlayerProgressBar: UICollectionView to later use it in xib. And can't seem to figure out how to properly use init functions
import UIKit
class AlbumPlayerProgressBar: UICollectionView, UICollectionViewDataSource {
var progressBarType :ProgressBarType = .Player
var numOfSlides: Int = 0
var numOfPlayingSlide: Int = 0
init()
{
super.init()
self.register(UINib(nibName: NSStringFromClass(ProgressBarCell.self), bundle: nil), forCellWithReuseIdentifier: NSStringFromClass(ProgressBarCell.self))
}
func set(progressBarType :ProgressBarType, numOfSlides: Int, numOfPlayingSlide: Int) {
self.progressBarType = progressBarType
self.numOfSlides = numOfSlides
self.numOfPlayingSlide = numOfPlayingSlide
self.reloadData()
}
required init?(coder aDecoder: NSCoder) {
fatalError("AlbumPlayerProgressBar init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numOfSlides
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(ProgressBarCell.self), for: indexPath) as! ProgressBarCell
cell.setType(self.progressBarType)
if (indexPath.row < numOfPlayingSlide)
{
cell.setPlayed()
}
else if (indexPath.row == numOfPlayingSlide)
{
cell.setPlaying()
}
else
{
cell.setUnplayed()
}
return cell
}
}
enum ProgressBarType {
case Player
case Thumnail
}

You can declare your CollectionView as
class AlbumPlayerProgressBar: UICollectionView, UICollectionViewDataSource {
var progressBarType :ProgressBarType = .Player
var numOfSlides: Int = 0
var numOfPlayingSlide: Int = 0
override func awakeFromNib() {
super.awakeFromNib()
//gets called when you instantiate your collectionView from xib
self.register(UINib(nibName: NSStringFromClass(ProgressBarCell.self), bundle: nil), forCellWithReuseIdentifier: NSStringFromClass(ProgressBarCell.self))
self.dataSource = self
}
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
self.register(UINib(nibName: NSStringFromClass(ProgressBarCell.self), bundle: nil), forCellWithReuseIdentifier: NSStringFromClass(ProgressBarCell.self))
self.dataSource = self
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.register(UINib(nibName: NSStringFromClass(ProgressBarCell.self), bundle: nil), forCellWithReuseIdentifier: NSStringFromClass(ProgressBarCell.self))
self.dataSource = self
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return numOfSlides
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: NSStringFromClass(ProgressBarCell.self), for: indexPath) as! ProgressBarCell
cell.setType(self.progressBarType)
if (indexPath.row < numOfPlayingSlide)
{
cell.setPlayed()
}
else if (indexPath.row == numOfPlayingSlide)
{
cell.setPlaying()
}
else
{
cell.setUnplayed()
}
return cell
}
}
Depending on how would you initialize/instantiate collectionView decide where would like to register your nib and setting data source as self.
Hope it helps

Related

Delegate methods in child class not called when using generics

I have a very similar problem to this question and this question and I think they might be related. The difference is that the delegate is not called when a generic view model is used.
In the first example below everything works as expected. Initialize a ViewController, which is a subclass of SimpleListViewController. When the cell is selected it prints "Here" because the superclass (SimpleListViewController) conforms to UICollectionViewDelegate.
class SimpleListVCModel {
var dataSource: UICollectionViewDiffableDataSource<Section, String>! = nil
var items = Array(0..<10).map{"This is item \($0)"}
enum Section: String {
case main
}
func configureDataSource(using collectionView: UICollectionView) {
let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { (cell, indexPath, item) in
var content = cell.defaultContentConfiguration()
content.text = "\(item)"
cell.contentConfiguration = content
}
dataSource = UICollectionViewDiffableDataSource<Section, String>(collectionView: collectionView) {
(collectionView: UICollectionView, indexPath: IndexPath, identifier: String) -> UICollectionViewCell? in
return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
}
}
func applySnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
snapshot.appendSections([.main])
snapshot.appendItems(items)
dataSource.apply(snapshot, animatingDifferences: false)
}
}
class ViewController: SimpleListViewController {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "List"
view.backgroundColor = .red
configureHierarchy()
model.configureDataSource(using: collectionView)
model.applySnapshot()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Here")
}
}
class SimpleListViewController: UIViewController, UICollectionViewDelegate {
var collectionView: UICollectionView! = nil
let model = SimpleListVCModel()
func configureHierarchy() {
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .insetGrouped))
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.delegate = self
view.addSubview(collectionView)
}
}
Now If I introduce generics, the collectionView delegate function is never called.
First create a subclass of SimpleListVCModel specifically for the ViewController.
class ViewControllerViewModel: SimpleListVCModel {
func foo(){
print("Foo")
}
}
Then slightly modify SimpleListViewController to use a generic SimpleListVCModel.
class SimpleListViewController<M: SimpleListVCModel>: UIViewController, UICollectionViewDelegate {
let model: M
var collectionView: UICollectionView! = nil
//MARK: - Initializer
init(model: M) {
self.model = model
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Views
func configureHierarchy() {
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .insetGrouped))
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.delegate = self
view.addSubview(collectionView)
}
}
Finally modify ViewController to use a generic version of the SimpleListVCModel.
class ViewController: SimpleListViewController<ViewControllerViewModel> {
override init(model: ViewControllerViewModel = ViewControllerViewModel()) {
super.init(model: model)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "List"
view.backgroundColor = .red
configureHierarchy()
model.configureDataSource(using: collectionView)
model.applySnapshot()
model.foo()
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Here")
}
}
This does appear to be similar to the case in the answer I linked to in comments, but since it's a little different I'll post this answer here.
First, in your SimpleListViewController, implement didSelectItemAt:
class SimpleListViewController<M: SimpleListVCModel>: UIViewController, UICollectionViewDelegate {
let model: M
var collectionView: UICollectionView! = nil
//MARK: - Initializer
init(model: M) {
self.model = model
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Views
func configureHierarchy() {
let layout = UICollectionViewCompositionalLayout.list(using: .init(appearance: .insetGrouped))
collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
collectionView.delegate = self
view.addSubview(collectionView)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item: \(indexPath) in SimpleListViewController")
}
}
When you do that, you'll see an error in ViewController:
Overriding declaration requires an 'override' keyword
For the moment, comment out your didSelectItemAt func in ViewController.
Now, when you select an item, didSelectItemAt in SimpleListViewController will be called and it will print to the debug console.
Next, un-comment didSelectItemAt in ViewController and add the override keyword:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item: \(indexPath) in ViewController")
}
Running the app now and selecting an item will call that func and print to the debug console.
Note that you can also call super ... so, if you have some default code you want executed in SimpleListViewController:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item: \(indexPath) in SimpleListViewController")
// do something common
}
and in ViewController:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
super.collectionView(collectionView, didSelectItemAt: indexPath)
print("Selected item: \(indexPath) in ViewController")
}
and you'll get both print statements in the debug console.
If you'd rather not do it that way, you can remove the implementation from SimpleListViewController and instead declare the #objc method signature in ViewController:
class ViewController: SimpleListViewController<ViewControllerViewModel> {
override init(model: ViewControllerViewModel = ViewControllerViewModel()) {
super.init(model: model)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "List"
view.backgroundColor = .red
configureHierarchy()
model.configureDataSource(using: collectionView)
model.applySnapshot()
model.foo()
}
#objc (collectionView:didSelectItemAtIndexPath:)
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("Selected item: \(indexPath) in ViewController")
}
}
Note that you can no longer call super with that approach.

Data Source for CollectionView inside CollectionViewCell is always nil

I have a UICollectionView inside a UICollectionViewCell, and a separate NSObject that is the dataSource. I am able to set the dataSource for the external UICollectionView, but not the internal one.
Here's the cell containing the internal UICollectionView:
class FeaturedCell: UICollectionViewCell, UICollectionViewDelegate {
#IBOutlet var collectionView: UICollectionView!
let data = FeaturedData()
override init(frame: CGRect) {
super.init(frame: frame)
//setUp()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
func setUp() {
collectionView.dataSource = data
collectionView.delegate = self
collectionView.reloadData()
}
}
extension FeaturedCell {
func setCollectionViewDataSourceDelegate <D: FeaturedData> (_ dataSourceDelegate: D, forRow row: Int) {
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.reloadData()
print("Reload Data")
}
}
And the UIView containing the external UICollectionView:
class MainView: UIView, UICollectionViewDelegate {
#IBOutlet var collectionView: UICollectionView!
let data = MainData()
override func awakeFromNib() {
setUp()
}
func setUp() {
collectionView.dataSource = data
collectionView.delegate = self
collectionView.backgroundColor = UIColor.orange
collectionView.collectionViewLayout = createLayout()
collectionView.isPagingEnabled = true
collectionView.bounces = false
collectionView.allowsSelection = true
}
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print("WillDisplay")
guard let cell: FeaturedCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeaturedCell", for: indexPath) as? FeaturedCell else {
fatalError("Unable to dequeue FeaturedCell.")
}
cell.setCollectionViewDataSourceDelegate(featuredData, forRow: indexPath.item)
}
}
Both of these methods are being called, but the dataSource and delegates are never being set. I also followed this tutorial exactly (with a UITableView, even) and it still would not set the dataSource or delegate. What am I doing wrong?
I think this will help
class FeaturedCell: UICollectionViewCell {
#IBOutlet var collectionView: UICollectionView!
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
extension FeaturedCell {
func setCollectionViewDataSourceDelegate <T: UICollectionViewDelegate , D: FeaturedData> (delegate: T dataSource: D, forRow row: Int) {
collectionView.delegate = delegate
collectionView.dataSource = dataSource
collectionView.reloadData()
print("Reload Data")
}
}
and in the MainView
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print("WillDisplay")
guard let cell: FeaturedCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeaturedCell", for: indexPath) as? FeaturedCell else {
fatalError("Unable to dequeue FeaturedCell.")
}
cell.setCollectionViewDataSourceDelegate(self, featuredData, forRow: indexPath.item)
}
And for the tutorial you followed this a Github link for the tutorial, compare your code with that and see where did you missed out.
Hope this will helps.
Solved it. The problem was that this:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print("WillDisplay")
guard let cell: FeaturedCell = collectionView.dequeueReusableCell(withReuseIdentifier: "FeaturedCell", for: indexPath) as? FeaturedCell else {
fatalError("Unable to dequeue FeaturedCell.")
}
cell.setCollectionViewDataSourceDelegate(featuredData, forRow: indexPath.item)
}
Needed to be changed to this:
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
print("WillDisplay")
guard let featuredCell = cell as? FeaturedCell else { return }
featuredCell.setCollectionViewDataSourceDelegate(featuredData, forRow: indexPath.item)
}

Cell from xib does not autoresize

I am trying to create infinite calendar using swift 3.0 + xib. I have 2 .xib files: JKCalendar (collectionView) and JKCalenderCell(date cell). When I use my JKCalendar class on UIView i get calendar that fits this view size, but my cells are off. What is more I cant set correct number of columns using FlowDelegate.
class JKCalendarCell: UICollectionViewCell {
#IBOutlet var test: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override init(frame: CGRect) {
super.init(frame: frame)
let view = Bundle.main.loadNibNamed("JKCalendarCell", owner: self, options: nil)?[0] as! UIView
addSubview(view)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
class JKCalendar: UIView,UICollectionViewDataSource,UICollectionViewDelegate,UICollectionViewDelegateFlowLayout {
#IBOutlet var collectionView: UICollectionView!
override func awakeFromNib() {
super.awakeFromNib()
self.collectionView.frame = self.bounds
self.collectionView.translatesAutoresizingMaskIntoConstraints = true
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadXib()
}
func loadXib(){
let view = UINib(nibName: "JKCalendar", bundle: nil).instantiate(withOwner: self, options: nil)[0]
addSubview(view as! UIView)
self.collectionView.register(UINib(nibName: "JKCalendarHeader" , bundle: nil), forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "JKCalenderHeader")
self.collectionView.register(JKCalendarCell.self, forCellWithReuseIdentifier: "JKCalendarCell")
}
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 42
}
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "JKCalendarCell", for: indexPath) as! JKCalendarCell
return cell
}
public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
let cell = cell as! JKCalendarCell
let dayNumber = countDayNumber()
cell.test.text = "\(dayNumber)"
cell.backgroundColor = UIColor.white
if indexPath.row % 2 == 0 {
cell.backgroundColor = UIColor.red
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = (collectionView.frame.width / 7.0 )
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
JKCalendar.xib
My ViewContoller
And this is what I get after running.
I want 7 cells/row with label in center. I used red color cells with label on right to show how much they are off

iOS swift custom UICollectionView with Custom Cell does not call didSelectItem

I got some issues with the following code: I created a custom Cell with a Custom UICollectionView class. I used Xib files instead of the storyboard.
It never calls the didSelectItemAtIndexPath method but why? I am really desperate :'(.
import UIKit
class CustomCollectionView: UICollectionView, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var refreshControl : UIRefreshControl = UIRefreshControl()
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.delegate = self
self.dataSource = self
var flowLayout:UICollectionViewFlowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = UICollectionViewScrollDirection.Vertical
self.collectionViewLayout = flowLayout
self.refreshControl.addTarget(self, action: "refreshData:", forControlEvents: UIControlEvents.ValueChanged)
self.addSubview(refreshControl)
self.userInteractionEnabled = true
self.registerClass(CustomCollectionViewCell.self, forCellWithReuseIdentifier: "outfit")
self.registerNib(UINib(nibName: layoutHelper.getCellXibName("CustomCollectionViewCell"), bundle: nil), forCellWithReuseIdentifier: "outfit")
self.backgroundColor = UIColor.whiteColor()
}
//
// MARK: UICollectionViewDataSource - Methods
//
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell : CustomCollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("outfit", forIndexPath: indexPath) as! CustomCollectionViewCell
cell.label.text = "Outfit #" + String(indexPath.row)
let url = NSURL(string: "http://placehold.it/177x370")
cell.imageView.sd_setImageWithURL(url, completed: nil)
return cell
}
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
println("at index path %i", indexPath.row)
}

UICollectionView in a UICollectionViewCell

I am interested in having a collectionview as a part of a collection view cell but for some reason cannot figure out how this would be done. Where would I implement the necessary methods for the cells collectionview?
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.
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
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
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{
}

Resources