viewForSupplementaryElementOfKind is not getting called - ios

i have declared collection view like below
lazy var collectionView:UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.minimumLineSpacing = 52
layout.sectionInset = UIEdgeInsets(top: 25, left: 0, bottom: 30, right: 0)
var collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.white
collectionView.showsVerticalScrollIndicator = false
collectionView.register(XXXCollectionViewCell.self, forCellWithReuseIdentifier: reuseIdentifier)
collectionView.register(XXXHeaderViewCell.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifier)
collectionView.delegate = self
return collectionView
}()
and implemented below delegates , control comes only to referenceSizeForHeaderInSection method but not to viewForSupplementaryElementOfKind
public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifier, for: indexPath)
return headerView
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
let size = CGSize(width: self.collectionView.bounds.width, height: 200)
return size
}
Any help is really appreciated.

I was facing the same issue and then figured out a solution.
try to add #objc (collectionView:viewForSupplementaryElementOfKind:atIndexPath:) just above your func collectionView(viewForSupplementaryElementOfKind:at:).
It seems that the obj-C and Swift have different names.
Look at the last param, on obj-C we have atIndexPath while on Swift we have just at.
Was that helpful?

Related

Pure code builds the collection but UICollectionViewDelegateFlowLayout is not executed

Pure code (I didn't use the storyboard, just use code) builds the collection but UICollectionViewDelegateFlowLayout is not executed.
class Calendarview : UIView , UICollectionViewDelegate , UICollectionViewDataSource , UICollectionViewDelegateFlowLayout {
var collectionview : UICollectionView!
override func didAddSubview(_ subview: UIView) {
}
override func didMoveToSuperview() {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
collectionview = UICollectionView(frame: CGRect(x: 0, y: 0, width: self.bounds.width, height: self.bounds.height) , collectionViewLayout: layout)
collectionview.frame = self.frame
collectionview.register(CalendarCell.self, forCellWithReuseIdentifier: "Cell")
collectionview.dataSource = self
collectionview.delegate = self
self.addSubview(collectionview!)
collectionview.reloadData()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 42
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
return CGSize(width: self.bounds.width / 7, height: self.bounds.height / 3)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! CalendarCell
cell.lbshow = UILabel(frame: cell.bounds)
cell.lbshow.text = String(indexPath.row)
cell.addSubview(cell.lbshow)
cell.backgroundColor = .blue
return cell
}
}
Set delegate as self.collectionView.delegate = self;. UICollectionViewDelegateFlowLayout inherits from UICollectionViewDelegate. So it will called all methods of UICollectionViewDelegateFlowLayout.
Hence, You need to set self.collectionView.collectionViewLayout to your flow layout.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: 10, height: 10)
layout.itemSize = CGSize(width: 200, height: 200)
layout.minimumLineSpacing = 10
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.scrollDirection = .horizontal
collectionview.collectionViewLayout = layout

Why aren't my collection view cells showing...?

It's been a while since I programmatically created a collection view and I can't seem to find why my cells are not showing. Delegate and Datasource are being set. Size is being set and it is not too big.
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "cellId"
override func viewDidLoad() {
super.viewDidLoad()
setupCV()
}
var containerCollectionView: UICollectionView = {
let layout = UICollectionViewLayout()
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = UIColor.white
return cv
}()
}
extension ViewController {
fileprivate func setupCV() {
// these first two lines add the colelction view and apply constraints - they work and the CV is properly displayed inside the view controller
self.view.addSubview(containerCollectionView)
containerCollectionView.anchor(view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, topConstant: 0, leftConstant: 0, bottomConstant: 0, rightConstant: 0, widthConstant: 0, heightConstant: 0)
containerCollectionView.delegate = self
containerCollectionView.dataSource = self
containerCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 150, height: 150)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath)
cell.backgroundColor = UIColor.yellow
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
}
You are initializing the wrong layout.
try this:
let layout = UICollectionViewFlowLayout()

Add CollectionView as Table View Header

I want to show banner like this:
My approach is adding a CollectionView as a TableViewHeader
My code:
extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func configureHeaderView() {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
let headerView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: headerHeight), collectionViewLayout: layout)
headerView.backgroundColor = .blue
headerView.isPagingEnabled = true
headerView.isUserInteractionEnabled = true
headerView.dataSource = self
headerView.delegate = self
headerView.register(BannerCollectionViewCell.self, forCellWithReuseIdentifier: BannerCollectionViewCell.reuseIdentifier)
headerView.showsHorizontalScrollIndicator = false
tableView.tableHeaderView = headerView
}
// MARK: UICollectionViewDataSource
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BannerCollectionViewCell.reuseIdentifier, for: indexPath) as! BannerCollectionViewCell
return cell
}
// MARK: UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: headerHeight)
}
}
My BannerCollectionViewCell has a default image.
class BannerCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var bannerImageView: UIImageView!
}
But I don't see that image on my header. It just show an empty header.
you use the NIB, so you should use func register(UINib?, forCellWithReuseIdentifier: String) instead of func register(AnyClass?, forCellWithReuseIdentifier: String)
Maybe you're looking for an image pager like KIImagePager on the top instead of a collection view. You can also create the same using inbuilt PageViewController.
You can add a TableView separately below this.

UICollectionViewController Error in Swift 3.0: must be initialized with a non-nil layout parameter

I'm new to iOS development.
I've been learning Swift, and today, I tried using UICollectionViewController.
My code is as follows:
class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var colView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 120)
colView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
colView.dataSource = self
colView.delegate = self
colView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
colView.backgroundColor = UIColor.white
self.view.addSubview(colView)
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 14
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
However, when I try to run it, I get the following error:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'
I have looked up previous posts discussing this issue, but I couldn't find anything that fixed my code.
How should I fix this?
Thank you! I incorporated your suggestions. Below is the code that works:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "CellId"
var colView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 111, height: 111)
colView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
colView.delegate = self
colView.dataSource = self
colView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
colView.backgroundColor = UIColor.white
self.view.addSubview(colView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 21
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath as IndexPath)
cell.backgroundColor = UIColor.orange
return cell
}
}
Again, thank you guys very much. Have an awesome day :D
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
let cellSize = CGSize(width: 90, height: 120)
//
return CGSizeMake(cellSize)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsetsMake(top: 20, left: 10, bottom: 10, right: 10)
}
This should work:
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
return collectionView
}()
Just change the order like below one :
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
layout.itemSize = CGSize(width: 90, height: 120)
colView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
self.view.addSubview(colView)
colView.delegate = self
colView.dataSource = self
colView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
colView.backgroundColor = UIColor.white
You can set your code like this:
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
let cellId = "Cell"
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
// ... layout parameters
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
cv.backgroundColor = .white
cv.delegate = self
cv.dataSource = self
return cv
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
// ... add your auto layout constraints to the collection view
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellId)
}
// Delegate and Data Source Methods...
}

Header not showing in UICollectionViewController Swift

I am trying to add a header to my UICollectionViewController. I have done this all through storyboard. When I run the app it doesn't show up.
This is what I am trying to display in my header:
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "Header", forIndexPath: indexPath) as! ProfileCollectionReusableView
header.editProfileButton.layer.cornerRadius = 5
header.nameLabel.adjustsFontSizeToFitWidth = true
header.nameLabel.text = PFUser.currentUser()!["name"] as? String
header.profilePictureImageView.layer.cornerRadius = header.profilePictureImageView.frame.size.height/2
header.profilePictureImageView.layer.masksToBounds = true
header.profilePictureImageView.layer.borderColor = UIColor.whiteColor().CGColor
return header
}
I am not seeing any errors on the console nor does the app crash. There is just a white screen with the navigation bars title updated to the users username.
if use .xib
let nib1:UINib = UINib(nibName: "ScheduleHeaderView", bundle: nil)
self.myCollection.register(nib1, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "ScheduleHeaderView")
set size for header
let layout = self.myCollection.collectionViewLayout as! UICollectionViewFlowLayout
layout.headerReferenceSize = CGSize(width: 50, height: 180)
UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header:ScheduleHeaderView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "ScheduleHeaderView", for: indexPath) as! ScheduleHeaderView
return header
}
Here are some tips you need to pay attention to what you have to do:
1.Implement UICollectionViewDelegateFlowLayout like:
class MyCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {}
2.register header class before you use :
self.collectionView!.registerClass(HeaderClass.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "header")
in the method ViewDidLoad();
3.set the size in the UICollectionViewDelegateFlowLayout like UITableViewDelegate
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSizeMake(Config.PHONE_WIDTH, 55)
}
4.return your own header like what you already done:
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
}
The issue could very well be with the height of the header section. I encountered the similar issue where I was registering the header but then the height was not set.
let layout = UICollectionViewFlowLayout()
layout.itemSize = CGSize(width: 20, height: 20)
layout.minimumInteritemSpacing = 10
layout.minimumLineSpacing = 10
let collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.white //default background color is black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
collectionView.register(Header.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: "HeaderCell")
//setting the height helped it in displaying on the page
layout.headerReferenceSize = CGSize(width: 50, height: 180)
To show header just make sure you have this code in your code with number "1", like this:
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}

Resources