UICollectionView loads more cells other than visible ones - ios

I have a UICollectionView, which has 2k+ records. At anytime only 6-7 rows will be visible and I'm using reusable cells. Everything works fine.
But when I make a console log in cellForRowAtIndexPath, initially 80+ rows are being loaded. After that it loads 1st 7 rows again, and properly loads only the visible cells.
Why does it load 80+ rows initially. This make a slight lag in initial loading.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return results.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
print("Cell For Row -> \(indexPath)")
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ResultCell", for: indexPath) as! ResultCell
cell.data = result[indexPath.item]
return cell
}
UPDATE:
I was using auto-sizing cells. So I did define estimatedItemSize as UICollectionViewFlowLayoutAutomaticSize
I tried defining a proper CGSize instead of UICollectionViewFlowLayoutAutomaticSize. And the extra cells stopped loading.

While performing autosizing cells, we give estimatedItemSize.
On using UICollectionViewFlowLayoutAutomaticSize for estimatedItemSize, the collectionview tries to load a countable number of cells (visible and non-visible) and get the estimated size.
If a proper CGSize (estimated) is given, the extra cells(non-visible) would be loaded less. So, the closer your estimated size is, the lesser non-visible cells are loaded.

Related

Creating tinder like card layout using UICollectionView

I am trying to recreate the tinder card stack which can then be swiped through. I have decided to do this using UIcollectionView.
I was going to make an array of user objects and within each, there would be an array of images. So for the number of sections, I would say arr.count and for the number of sub-sections arr[section].arrImg.count.
Currently, I have a problem where when I run the project I get a vertical stack of 5 images. I assume each image represents one cell. But I need these cells to be stacked on top of each other like tinder.
How can I do that (stacked on top of each other like tinder)?
The logic for making the card layout:
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(peopleArr[section].arrOfProfileImages.count, "jfldhsajklfhsdkj")
return peopleArr[section].arrOfProfileImages.count
}
//This current version loads all people it should only return like 3...
func numberOfSections(in collectionView: UICollectionView) -> Int {
print("fkhdsgafhjdgsajhfgdsak", peopleArr.count)
return peopleArr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cardCell", for: indexPath) as! DatingCardCollectionViewCell
cell.imageView.image = UIImage(named: "ProfileImage")//peopleArr[indexPath.row].arrOfProfileImages[indexPath.section]
return cell
}

Swift UICollection view different number of cells per row

How can I have a UICollection View, with One cell in the first row, and three cells in the second row?
I want to display a picture in the first row, and below it 3 pictures.
You need to use collectionView's Datasource method number of section to specify how many section you required in your collectionview. in that section you can pass number of cell you want to display. and in cell for item you can set data according to section and Item value.
try like this.
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3 // you can return as per your requirement
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 2 // number of cell you want to display in each section
}else if section == 1 {
return 3 // number of cell you want to display in each section
}else {
return 4 // number of cell you want to display in each section
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifierCollection, for: indexPath) as! HomeCollectionViewCell
return cell
}
You need to implement your own custom layout. By default the collection view has UICollectionViewFlowLayout, that fills the cells in a horizontal/vertical grid.
You can change this behaviour with your own layout, i.e. a class implementing UICollectionViewLayout.
To get started, I would recommend checking this and this tutorials.

In UICollectionView, the order changes automatically

I have a big problem.
I scrolled in the UICollectionView.
When the drawing area is scrolled too much, the arrangement order has become disjointed.
I do not want to change the order even though scrolling.
What should I do?
help me.
let titles = ["1","2","3","4","5","6","7","8", "9", "10", "11", "12"] //titles
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = testCollectionView.dequeueReusableCell(withReuseIdentifier: "TestCell", for: indexPath) as! TestCell //customCell
let testTitle = cell.contentView.viewWithTag(2) as! UILabel
testTitle.text = titles[indexPath.row]
return cell // yeah, all done. is these code is normal. right? But when i scroll this UICollection, change the order in Outside drawing area.
}
You should definitely not be using viewWithTag. The reason for this is because cells are dequeued, which means that cells that have been taken off screen by scrolling are reused for the cells which are about to come on screen. This is done to save memory. Sometimes the problem with the order can be because previously used cells are not updated quick enough when they are presented to the user. The solution to this if you are using a network request can be to firstly to streamline your request and then cache any heavy data that is returned, such as images.
Your code should not be causing the cells to change order. I'm wondering if you have a problem with using viewWithTag. That's a fairly fragile way to find views in a collection view/table view cell.
You already have a custom cell type. I would suggest creating an outlet to your label in your custom cell type, and referencing the label that way:
class TestCell: UICollectionViewCell {
//(Connect this outlet in your cell prototype in your Storyboard
#IBOutlet titleLabel: UILabel!
}
//And in your view controller's cellForItemAt method...
cell.titleLabel.text = titles[indexPath.row]

Swift - separate views have subviews that are sharing the same memory?

new to swift. I have a nested CollectionView from one viewcontroller. The main viewcontroller has 7 collectionviewcell ("Level1Cell" in the code below). Each time I click a button or trigger an event, I want the collectionView to reload with the new data.
func eventHandler() {
// updates data
myCollectionView.reloadData()
}
Then, after it calls reload, it will call the reload again on each of the the nested CollectionViewCell.
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Level1Cell", for: indexPath) as! Level1Cell
cell.appsCollectionView.reloadData()
return cell
}
The problem is, let say I want to, for the first cell, set a particular row some text.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(self.index == 0 && indexPath.row == 30){
rightCell.textLabel.text = "asdasd"
}
The fourth "Level1Cell" cell somehow has its label set also at the 30th row, but not the second and third. After stepping through the debugger, I realize that the cells, after reloading, the fourth cell "Level1Cell" is set to have the the same memory address as the first cell ( why does reload do this - shouldn't it allocate a new memory for each "Level1Cell"? - how can I get around this). Also, should I not use reload to update the data in the view and nested view of those from the view controller?
Thanks!
UIcollectionview will reuse cells. You must provide needed data for row in method
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
Or just clear previous data at cell.

Autoresize UICollectionViewCell size inside UITableView

I am trying to create simple educational app about movies, and I need to create movie frames horizontal scroller.
I create collection view for that:
But if I build it for another target (iPhone 6s Plus for example), I have this:
How to solve this problem?
My scene controller code (Swift 3):
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 4
}
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath)
cell.backgroundColor = UIColor.black
// Configure the cell
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
I think that you can try to implement the method of UICollectionView delegate:
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSizeMake(yourHeight, self.view.frame.size.width)
}
in this way, your collectionView-cell inside in tableView will appear as big as the screen.
First I want to say something about UITableViewAutomaticDimension you use, in case you not exactly understand how it works.
Your expectations probably are, that UITableViewAutomaticDimension will infer tableView to make a cell with size of entire tableView, but it doesn't work this way.
UITableViewAutomaticDimension is just infers tableView, that inner size of your cell will be used as a returned here; so if you add some constraints, views with constraints, or whatever inside your tV, its size will be used.
and second - your comment doesn't make sense at all for me, because your posted code isn't related to cell of collectionView and I can't comment anything related to size of its cells
EDITED:
to make all cells with width of your screen, return correct size from delegate method of collectionViewFlowLayout - sizeForItem

Resources