numberOfItemsInSection is called but cellForItemAt is not called UICollectionViewController - ios

This maybe a duplicate post. But I haven't found any solution in the answers given in previous questions.
Basic checks from my side that I have done.
No errors on the constraint that I have put on CollectionView and CollectionViewCell.
When numberofitemsinsection is called, it always returns more than 0.
Reusable identifier is tagged for both CollectionView and CollectionViewCell
All links for ui objects are at place.
CollectionViewCell size is set as default.
Some more information on my code.
class StickerGridCollectionViewController: UICollectionViewController{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stickerPackList.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/*some code*/
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
/*some code*/
}
}
I checked all the answers here, but didn't find my answer yet.
Any clue why I might be getting this issue?
Update
When I open debug view hierarchy, I find out that collectionview is taking correct area, but views which were supposed to be inside collectionview are flowing outside and acting abnormally.
Moreover I see UICollectionView inside UiCollectionView.
Any reason, why this abnormal behaviour might occur?

Related

UICollectionView cellForItemAt is called twice when scrolling

I have a UICollectionView with the following settings:
Estimate Size = None
Content Insets = Never
Scroll Direction = Vertical
Paging Enabled = true
When I scroll to the second cell, the cellForItemAt method is triggered twice, with indexes 1 and 2 at the same time, and accordingly, when I swipe to the last cell, the cellForItemAt method does not work.
cellForItemAt does not work correctly only on swiping to the second cell, in all other cases it is OK (one index per swipe)
I also noticed that cellForItemAt is triggered not as soon as a new visible cell appears, but with a delay (about 100 pixels on top, the standard height is 568 pixels of cells)
Because of this problem, I do not work cellForItemAt on the last cell, also in the cells there are photos that are loaded by URL (I tried without loading images, the problem is the same), and they are in random cells, this is also a problem.
I do not know how to explain and solve this issue, thank you for any help
UP
override func viewDidLoad() {
super.viewDidLoad()
collectionView.register(UINib(nibName: TestCell.identifier, bundle: nil), forCellWithReuseIdentifier: TestCell.identifier)
collectionView.dataSource = self
collectionView.delegate = self
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("cellForItemAt: \(indexPath.item)")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TestCell.identifier, for: indexPath) as! TestCell
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
If I scroll to the second cell, the cellForItemAt works twice, and when the last cell, the cellForItemAt does not work at all. Accordingly, the configuration methods for the last cell do not work. I gave a simple example, but the problem is the same.
How do I load a cell on a user's scroll correctly?
As #PaulW11 said in his comment, your data source's collectionView(_:cellForItemAt:) method can be called at any time, with any indexPath. You should code your data source to provide any cell, for any valid indexPath, at any time, in any order.
The only limitation is that the collection view first calls your data source's numberOfSections(in:) and collectionView(_:numberOfItemsInSection:) methods, and won't ask for a cell for an indexPath that is out of the valid ranges indicated by those methods. Other than that, you should not make any assumptions about the cells the collection view will ask for, or the order in which it requests them.

Swift UICollectionView Cell being rendered twice

I am writing a customer calendar as a challenge for me to practice UICollectionView. This issue has been puzzled me for few days. So the problem is when it reuses the cell, the load data source function has been called twice or three times, then it leads to:
Sometimes it's called three times and my calendar days become 100 110 etc.
Here is the delegate and datasource code:
extension CalendarViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.calendarPages.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CalendarCell
cell.calendarPage = self.calendarPages[self.currentPageIndex]
cell.contentView.addSubview(self.buildCalendarPage(index: indexPath.row, frame: cell.contentView.frame)) // this is where it add new month page to the calendar, and it's randomly called multiple times
print("cell called")
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
}
I know what's going one there, so basically I made it too complicated, there is a calendar UICollectionView in another UICollectionView, (I just want to make it scrollable), so each time when the cell is reused, I forget to reload the UI
Solution, keep only one UICollectionView, each cell is a day, and create another UICollectionViewCell class to control the reusable cell, thanks for the Babar's help

Method not fired in UICollectionView when added within a UIStackview

I have added a UICollectionVIew to a vertical Stack View. I connected both datasource and Delegate from storyboard and added the delegate/datasource from the code as well.
However, the following method is not being called at all:
internal func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { ... }
But, the methods
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
are being called.
So, I moved the UICollectionVIew out of the vertical Stack View and it was working then. But, the method is not being called when the UICollectionVIew is in the vertical Stack View.
How can I solve this?
Same happen with me in past with TableView but not with UIStackView
If numberOfSections and numberOfItemsInSection called and cellForItemAt not called then only possible reason your CollectionView height is 0
Because of that your cell didn't get enough space to show cell
You can Check same thing by adding height of your collection view to 0
in to the case where you said I moved the UICollectionVIew out of the vertical Stack View and it was working then.

Creating a horizontal scrolling menu

I am trying to create a menu where top horizontal scrolling view contains the menu categories. When I tap on one of the menu categories, ads related to the category appears.
When First is selected
--**First**---|--Second--|---Third--|--Fourth--| (scrolling categories)
------------------------------------------------------------------
\\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\
\\\FirstA\\\ \\\FirstB\\\ \\\FirstC\\\ \\\FirstD\\\
------------------------------------------------------------------
When Second is selected
--First---|--**Second**--|---Third--|--Fourth--| (scrolling categories)
------------------------------------------------------------------
\\\SecondA\\\ \\\SecondB\\\ \\\SecondC\\\ \\\SecondD\\\
\\\SecondA\\\ \\\SecondB\\\ \\\SecondC\\\ \\\SecondD\\\
------------------------------------------------------------------
When I tap on First Category, data related to first comes as a collectionView. Similarly, when I tap on second Category, data related to second comes in the UICollectionView.
Now I am thinking of doing it in a UITableViewCell with two UICollectionViews. First UICollectionView will contain categories and second UICollectionView will contain data related to categories.
But I have never used two UICollectionViews in a single UITableViewCell.
So I am asking is it the correct approach for this type of requirement or should I do it in some other manner.
You could subclass an UITableViewCell, add UICollectionView as subview, conform UICollectionViewDataSource and UICollectionViewDelegate
here's sample code using xib
class CollectionViewTVC: UITableViewCell {
#IBOutlet weak var collectionView: UICollectionView!
}
extension CollectionViewTVC: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// return items
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
// return size
}
}
extension CollectionViewTVC: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// select cell action
}
}
Why don’t you use two table view cells, one for every collectionViewu?

CollectionViewDelegate method doesn't get called after Swift 3 migration

I have a simple collection view in my app, and I use the delegate to get notified when a cell was tapped, so I implement didSelectItemAtIndexPath: method. In Swift 2 this method's signature looked like this:
#objc func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
After running thru migration process this signature changed to this:
#objc func collectionView(collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
The compiler was happy and I moved on, but now this method doesn't get triggered when I tap any cell. I found a way to fix it:
#objc(collectionView:didSelectItemAtIndexPath:) func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
Obviously, the problem was in the first parameter name, but I still don't understand why it doesn't work without specifying obj-c selector explicitly.
no need to write #objc,
Here is a working code,
extension YourViewController:UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelect")
}
}
add delegate in viewdidload also add uicollectionviewdelegae,uicollectionviewdatasource also in storyboard,
this helps me.

Resources