I have the following implementation in the app, where there is a table view, where each table view cell holds a collection view.
Here, the number of cells in a collection view will depend on the data in a tableview cell and will be different for each row. For example, there are 3 cards in 1st row, 1 in 2nd row and 2 in 3rd row.
The issue is I am getting 3 collection view cells instead of 1 in the second cell.
Table view
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.groupedJobIds.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: JobTableViewCellCollection.CellReuseIdentifier) as? JobTableViewCellCollection {
var jobIds = self.groupedJobIds[indexPath.row]
cell.delegate = self
if jobIds != [] {
cell.bindJobs(jobIds)
}
return cell
}
return UITableViewCell()
}
Tableview cell / Collection view
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.jobIds.count //It returns 1
}
//This method is called 3 times
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: JobCollectionViewCell.CellReuseIdentifier, for: indexPath) as? JobCollectionViewCell
cell?.delegate = self
cell?.bindJob(jobId)
return cell!
}
As you can see, the first method returns 1 as numberOfItemsInSection. But the second method is called 3 times. Am I missing something?
I think you are using dequeueReusableCell method of the table view, which is causing the problem.
Can you try a new collection view on table view every time it load?
You should populate your UICollectionView from the right source. In your code you populate all of your collection view cells from the same self.groupedJobIds. You should either populate your collection view from table view cell's bound jobIds or keep an array of jobId groups in your UIViewController and populate from there.
I found a solution to this. I missed the reloadData() on the collection view which was causing the issue
Currently I'm using UICollectionView with several cells in it. UICollectionView scrolls horizontally to move between the cells.
My question is : Is there any way to call func(didSelectItemAt) by clicking the cell while its UICollectionView is on scrolling?
Here is gif.
Right after dragging cell to left for scrolling, I click the cell continuously to call func(didSelectItemAt) but it get call only when scrolling is finished. Is it possible to func(didSelectItemAt) to be called instantly right after clicking cell while on scrolling?
Here is my code for collectionView delegate & dataSource.
extension CardViewController : UICollectionViewDelegate,UICollectionViewDataSource {
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return cardCount
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = cardCollectionView.dequeueReusableCell(withReuseIdentifier: "card", for: indexPath) as! CardCell
cell.isFront = cellsSelectedStatus[indexPath.row]
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = cardCollectionView.cellForItem(at: indexPath) as! CardCell
UIView.transition(with: cell, duration: 0.3, options: [.transitionFlipFromLeft,.allowUserInteraction], animations: nil, completion: nil)
cellsSelectedStatus[indexPath.row] = !(cellsSelectedStatus[indexPath.row])
cell.isFront = cellsSelectedStatus[indexPath.row]
print("did select")
}
Collectionview’s dataSource&delegate are called in viewDidLoad.
I know there is allowUserInteraction from UIViewAnimationOptions which allows to click view while its being animated. Is there smilier code for func(didSelectItemAt)?
There’s no networking & UIGestureRecognizers is attached to the cell or collectionview.
So far I've set
isUserInteractionEnabled,
isMultipleTouchEnabled,
allowsMultipleSelection to true for collectionView,
but it still behaves the same.
I’m using Swift3, Xcode9.
Thanks in advance.
I am coding in Swift 3.2, and inside of a TableView Controller have a TableView (scrolling vertically), and each row of the table holds a CollectionView (scrolling horizontally).
I am not sure if it is acceptable coding practice, but I made my ViewController class inherit UITableViewController and UICollectionViewDelegate and UICollectionViewDataSource.
For now, I have a hard coded array of image names and would like three images to scroll horizontally in each collection view, with each row having distinct images. However, as of now each row shows the same three images ("11.png", "12.png", "13.png"), and I was wondering how to fix this.
Below is my ViewController class.
//for the tableView
let event = generateRandomData()
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return event.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
guard let tableViewCell = cell as? TableViewCell else { return }
tableViewCell.setCollectionViewDataSourceDelegate(self, forRow: indexPath.row)
}
//for the collectionView
var images: [String] = [
"11.png", "12.png", "13.png",
"21.png", "22.png", "23.png",
"31.png", "32.png", "33.png",
"41.png", "42.png", "43.png",
"51.png", "52.png", "53.png",
"61.png", "62.png", "63.png",
"71.png", "72.png", "73.png",
"81.png", "82.png", "83.png",
"91.png", "92.png", "93.png",
"101.png", "102.png", "103.png",
]
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
collectionView.isPagingEnabled = true; //makes the horizontal scrolling have no bounce and relatively have a better snap
let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath as IndexPath) as! CollectionViewCell
let myCellImage = UIImage(named: images[indexPath.row])
myCell.eventImage.image = myCellImage
return myCell
}
I am an amateur coder, so any help is greatly appreciated!
I am sure this problem already have an answer somewhere, but since I can't find that I'll just give one here.
Your mistake is here:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/...
let myCellImage = UIImage(named: images[indexPath.row]) //<< indexPath.row will return 0,1 and 2 for each of your collection view
/...
}
Each collection view in your table view does not communicate amongst themselves to form a larger collective view. Since all of the are provided the int of 3 for numberOfItemsInSection and their numberOfSections defaulted to 1(you did not set any), each of them will request for item at indexpath (0,0), (0,1) and (0,2) when trying to populate their data.
Your hardcoded array however, is an array with 30 items. So each collection view when requesting for cellForItemAt will only get 0,1 and 2 for images[indexPath.row]. Also you should use indexPath.item for collection view, indexPath.row is for table views, it may or may not work if used wrongly.
Solution
You can just set the tag property of the collection view to mark it's row:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
/...
//Make sure you have a subclass for UITableViewCell that have an IBOutlet that connects to the collection view
cell.collectionView.tag = indexPath.row //Note that this only works in your situation where the table view have only 1 section.
/...
}
Then split your array into a 2D array:
var images = [
["11.png", "12.png", "13.png"],
["21.png", "22.png", "23.png"],
["31.png", "32.png", "33.png"],
["41.png", "42.png", "43.png"],
["51.png", "52.png", "53.png"],
["61.png", "62.png", "63.png"],
["71.png", "72.png", "73.png"],
["81.png", "82.png", "83.png"],
["91.png", "92.png", "93.png"],
["101.png", "102.png", "103.png"]
]
Finally read the array in the collection view like:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/...
let myCellImage = UIImage(named: images[myCell.tag][indexPath.item])
/...
}
I have a UICollectionView and i want to save the data (images) always in the first cell and the old data walks to the next cells. So when i save a new photo it´s comes in the first cell, i have tried with indexpath.row == 0 {} in cellForRowAtIndexPath but he saves only in the first cell in the other cells are nothing. Can i invert the save index or give it a another way ??
So have anyone a idea what i can make there ??
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return picture.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier("BookPicCell", forIndexPath: indexPath) as! BookPicCell
let cellcore = picture[indexPath.row]
if indexPath.row == 0 {
cell.BookImage.image = UIImage(contentsOfFile: cellcore.foto!)
}
return cell
}
Thanks for your Help.
You need to create an array of UIImages and append the new image to the front of that array:
pictures.insert(newImage, atIndex : 0)
Than after you inserted your new image you need to reload your UICollectionView using:
self.collectionView.reloadData()
You do not want to sort your data inside the cellForItemAtIndexPath
Hi so I'm using a side scrolling UICollectionView to display groups of people that the user makes. The groups are stored on my server and when the view loads, they load from the server. However I want the first cell to always be the same which is a cell which lets you create groups. This is the layout i need.
I know how to use multiple different custom cells, but how do I make it so the first cell is static and the cells after load content from my servers? Thanks :)
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return familyName.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
if indexPath.row == 0 {
let cell : AddGroupCollectionViewCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Add", forIndexPath: indexPath) as! AddGroupCollectionViewCell
return cell
} else {
let cell : FriendGroupsCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as! FriendGroupsCell
cell.groupImage.image = UIImage(named: "pp")
cell.groupNameLabel.text = familyName[indexPath.row]
return cell
}
}
This is my code and it misses out the first person in the array because the index path skips over it. How can i modify this so it works
UICollectionViewCell is leveraging reusing techniques to improve performance. Remember this. Nothing can be static in a cell, because this cell later will be on another index.
You can use collectionView:cellForItemAtIndexPath: to make the first cell always load the same images/labels via indexPath.row == 0
You can use prepareReuse method to clean up the resources in the cell. So if cell No.2 is going to be the new No.1 cell, it get a chance to clean up old resources.
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell : AddGroupCollectionViewCell = collectionViewOutlet.dequeueReusableCellWithReuseIdentifier("Add", forIndexPath: indexPath) as! AddGroupCollectionViewCell
if indexPath.row == 0 {
cell.groupImage.image = UIImage(named: "new")
cell.groupNameLabel.text = "new"
} else {
cell.groupImage.image = UIImage(named: "pp")
cell.groupNameLabel.text = familyName[indexPath.row]
}
return cell
}