viewForSupplementaryElementOfKind is not being called in iOS 13 device - ios

I try to add footer view in my collection view layout with collection view delegate method viewForSupplementaryElementOfKind but it's not being called while reload collection view.
SeatArrangementViewController : UICollectionViewDelegate , UICollectionViewDataSource , QuiltViewDelegate ,UICollectionViewDelegateFlowLayout {
override func viewDidLoad() {
super.viewDidLoad()
setCollection()
}
func setCollection() {
self.clnSeats.collectionViewLayout.invalidateLayout()
self.clnSeats.register(UINib(nibName: "SeatFooterView",bundle:nil),forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: "SeatFooterView")
let space = UIScreen.main.bounds.size.width - 262
self.clnSeats.contentInset = UIEdgeInsets(top: 0, left: space/2.0, bottom: 90, right: space/2.0)
let layout = self.clnSeats.collectionViewLayout as! QuiltView
layout.scrollDirection = UICollectionViewScrollDirection.vertical
layout.itemBlockSize = CGSize(width: 50, height: 50)
self.clnSeats.reloadData()
}
Collection View Methods
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind{
case UICollectionElementKindSectionFooter: .....
}
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, blockSizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// get random width and height values for the cells
let width = self.numberWidths[indexPath.row]
let height = self.numberHeights[indexPath.row]
return CGSize(width: width, height: height)
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForItemAtIndexPath indexPath: IndexPath) -> UIEdgeInsets {
return UIEdgeInsets(top: 2, left: 2, bottom: 2, right: 2)
}
I also add #objc (collectionView:viewForSupplementaryElementOfKind:atIndexPath:) but that not work for me.

Check if you've registered a supplementary view.
Check if delegate and data source are set.
If you are using custom size for footer or header ensure that it returns a size that greater than zero otherwise delegate will stop trying to get a supplementary view
func collectionView(_ collectionView: UICollectionView,layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize

Related

UICollectionViewCells hiding behind headerView

Using UICollectionView with custom headers. Strange thing happening is custom cells hiding behind header cell. Below is code:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let reusableview = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "CalendarHeaderView", for: indexPath) as! CalendarHeaderView
switch kind {
case UICollectionView.elementKindSectionHeader:
reusableview.frame = CGRect(x: 0 , y: 0, width: self.view.frame.width, height: 40)
//do other header related calls or settups
reusableview.headerLabel.text = "Month"
return reusableview
default: fatalError("Unexpected element kind")
}
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = collectionView.bounds.width / 7.0
let height = width
return CGSize(width: width, height: height)
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
switch kind {
case UICollectionView.elementKindSectionHeader:
/// PROBLEM
reusableview.frame = CGRect(x: 0 , y: 0, width: self.view.frame.width, height: 40)
return reusableview
default: fatalError("Unexpected element kind")
}
}
You are not supposed to set the frame of UICollectionView.elementKindSectionHeader. UICollectionView does all of that for you. You just need to tell it how big (CGSize) it needs to be.
You can tell UICollectionView about this size via following method -
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 40)
}
}

Change UICollectionView cell X position - swift

How can I change the X position of every single cell programmatically? I can change the width and height of the cell as my wish but it is unable to complete the project because of XY position.
My result ,
Expected result is,
and my full view controller code is,
import UIKit
class ReviewVC: UIViewController , UICollectionViewDataSource , UICollectionViewDelegate , UICollectionViewDelegateFlowLayout{
var cellWidthArr : [CGFloat] = [60.0 , 170.0 , 110.0 , 120.0]
var titleArr = [" Polite " , " Showed up on time ", " Quick responses " , " Fair prices "]
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Review your experiance"
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
collectionView!.collectionViewLayout = layout
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ReviewCollectionCell", for: indexPath)as? ReviewCollectionCell
cell?.titleLabel.text = self.titleArr[indexPath.row]
cell?.titleLabel.layer.cornerRadius = (cell?.titleLabel.bounds.size.height)!/2
cell?.titleLabel.clipsToBounds = true
cell?.titleLabel.layer.borderColor = (UIColor.init(red: 240/255, green: 36/255, blue: 70/255, alpha: 1.0)).cgColor
cell?.titleLabel.layer.borderWidth = 1.0
return cell!
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: self.cellWidthArr[indexPath.row], height: 30)
}
}
Anyone please help me to findout the solution.Thanks...
You can use the open source project TagCellLayout written by riteshhgupta in GitHub.
Sample Code to initialize the layout:
import TagCellLayout
let tagCellLayout = TagCellLayout(alignment: .left, delegate: self)
collectionView.collectionViewLayout = tagCellLayout
I know you might write the lots of code for this, but it would be helpful greatly and even you can customize to different layout alignments.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return (ArrayName[indexPath.row] as NSString).size(withAttributes: nil)
}
Rather than giving Cell Fixed Size in an Array there is a way to find label size in sizeForItemAtIndexPath return the size of the text So it will find the size and work

Weird drawing when using UICollectionView created programmatically

I am creating a UICollectionView and its cells programatically. In my custom UICollectionView the only method that is implemented is layoutSubviews. Here is the code below for setting up my collection view and handling the delegation. As you can see from the gif once in a while a cell loads correctly, but the majority are misaligned or off screen. I suspect it is something wrong with how they are reused. I usually use tableviews and scrollviews, so I'm not as comfortable with collection views. How can I fix this?
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumInteritemSpacing = 0
layout.minimumLineSpacing = 0
layout.itemSize = CGSize(width: 160, height: 200)
featuredCollectionView = UICollectionView(frame: frame), collectionViewLayout: layout)
featuredCollectionView.delegate = self
featuredCollectionView.dataSource = self
featuredCollectionView.register(ItemCollectionViewCell.self, forCellWithReuseIdentifier:
"cell")
// MARK: CollectionView Delegate
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat
{
return 8
}
func numberOfSections(in collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
return CGSize(width: 160, height: featuredCollectionView.frame.size.height)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return featuredItems.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ItemCollectionViewCell
cell.item = featuredItems[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets
{
return UIEdgeInsetsMake(0, 0, 0, 0)
}
To see your main issue, check the frame of backgroundCardView, you're setting it based on the cell's origin within the collection view.
backgroundCardView.frame = CGRect(x: self.frame.origin.x + 8, y: self.frame.origin.x + 8, width: self.frame.size.width - 16, height: self.frame.size.height - 16)
This is going to be way outside the cell's bounds, which is why it appears to be laying out incorrectly. Also, you should add subviews to the cell's contentView instead of directly to it's view. As noted in other comments, you shouldn't add views in layoutSubviews. A better place would be inside an init method.

Set collectionView size. (sizeForItemAtIndexPath function is not working) Swift 3

I have a tableView and in every tableViewCell is a collectionView.
I am trying to change the collectionView size with this code:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
if collectionView.tag == 2{
return CGSize(width: 100, height: 100)
}else if collectionView.tag == 4 {
return CGSize(width: 222, height: 200)
}else{
return CGSize(width: 10, height: 10)
}
}
The problem is that there is no error but cells do not change sizes
If you need to know something more, just write a comment.
Thank you.
First, don't forget to extends from UICollectionViewDelegateFlowLayout delegate.
For single collectionview display logic :
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = ((collectionView.frame.width - 15) / 2) // 15 because of paddings
print("cell width : \(width)")
return CGSize(width: width, height: 200)
}
And important point in storyboard don't forget Estimate Size : None
The signature for this method has changed in Swift 3 to:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
// your code here
}
Pay attention to the subtle difference: (_ collectionView: ... instead of (collectionView: ....
This is because in Swift 3, you have to explicitly specify the label of the first parameter. You can override this default behaviour by adding the underscore character _.
Also, make sure that your class adopts both UICollectionViewDelegate and UICollectionViewDelegateFlowLayout protocols
class MyViewController: UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
// your code here
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
// your code here
}
}
Refer to this link to learn more about changes in Swift 3.
You need to specify that you implement the protocol UICollectionViewDelegateFlowLayout in your class declaration.
class PhrasesCompactCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout
So This is my code right now and it works:
collectionView.delegate = dataSourceDelegate
collectionView.dataSource = dataSourceDelegate
collectionView.tag = row
collectionView.setContentOffset(collectionView.contentOffset, animated:false)
collectionView.reloadData()
collectionView.register(UINib(nibName: "eventsCollectionViewCell", bundle: nil), forCellWithReuseIdentifier: "eventsCollectionViewCell")
if row == 2{
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: 120, height: 120)
layout.scrollDirection = .horizontal
collectionView.collectionViewLayout = layout
}else if row == 4 {
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
layout.itemSize = CGSize(width: 222, height: 200)
layout.scrollDirection = .horizontal
collectionView.collectionViewLayout = layout
}else{
print("else")
}
Short Version:
Try adding
collectionView.delegate = dataSource
Longer version:
For Me this was a small mistake -
collectionView.dataSource = self
This would call these methods
func numberOfSections(in collectionView: UICollectionView) -> Int
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
However it would NOT call
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize
Because this is not part of UICollectionView 's dataSource. It's part of UICollectionView's delegate.
So adding the following solved my issue.
collectionView.delegate = dataSource
I've had the same problem! If you make the size half the width (width/2), then it will still appear like the entire width because the padding is being added to the width/2.
Fix: Make sure to set the section insets in Storyboard to 0. Alternatively, adjust the width/2 to a size that INCLUDES the section insets.
It took me a while to fix that one ;-)
Don't forget to assign UICollectionViewFlowLayout object to your collectionViewLayout since UICollectionView uses UICollectionViewLayout (not UICollectionViewFlowLayout) by default.
let flowLayout = UICollectionViewFlowLayout()
collectionView.collectionViewLayout = flowLayout

UICollectionView: add spacing between header and items

I want to add some spacing between my header and the actual items, which currently look like this:
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
// Create header
switch kind{
case UICollectionElementKindSectionHeader:
let headerView = iconCollectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: "customIconHeaderView", forIndexPath: indexPath) as! CustonIconHeaderView
headerView.setUp() //add whatever into the view
return headerView
default:
assert(false, "Unexpected element kind")
}
}
You are basically talking about adding a top margin to the collection view section, for that you would set top inset for the section. To do it in code, implement insetForSectionAtIndex:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 10.0, left: 1.0, bottom: 1.0, right: 1.0)
}
If you don't want to implement the insetForSectionAtIndex, you could also do something like this in an appropriate method e.g. viewDidLoad:
let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
layout.sectionInset = UIEdgeInsets(top: 10.0, left: 1.0, bottom: 1.0, right: 1.0)
In Interface Builder, Select collection view and change the value for Section Insets -> Top as shown in the image below:
NOTE: This only works if you are using Flow Layout.
One way you can do is to increase your header container's heigh using
collectionView(_:layout:referenceSizeForHeaderInSection:)
Example:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: 0, height: yourHeaderContentHeight + yourHeaderMarginToCell)
}
Edit:
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(UICollectionElementKindSectionHeader, withReuseIdentifier: "YourID", forIndexPath: indexPath)
let yourCustomView = UIView(frame: CGRect(x: 0, y: 0, width: yourHeaderWidth, height: yourHeaderHeight))
headerView.addSubview(yourCustomView)
return headerView
}
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: yourHeaderWidth, height: yourHeaderHeight + yourHeaderMargin)
}

Resources