I am developing an application in swift where you have the possibility to filter the data displayed in the UICollectionView. After the data is filtered, collection view should update, so only items which fit the filter will be visible(eg. price is more than 30$). I can't update the collection view, I've tried literally everything...(reloadData(), deleteItems(at: IndexPath), batch, etc...) Here is the code for collection view functions:
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return dogsSort.count
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 150)
}
internal func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
selectedDog = dogsSort[indexPath.row]
print("selected dog " + selectedDog.name)
let vc = self.storyboard!.instantiateViewController(withIdentifier: "ItemVC") as! ItemViewController
vc.dog = selectedDog
self.navigationController!.pushViewController(vc, animated: true)
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! CollectionViewCell
cell.imageView.layer.cornerRadius = 10
/*storageWizard.getImage(path: "/dogs/" + dogsSort[indexPath.row].id + "/image.png", imageCompletionHandler: { (image) -> Void in
cell.imageView.image = image
self.dogsSort[indexPath.row].image = image
return
})*/
print(indexPath.row)
if dogsSort.count > indexPath.row {
cell.btnPrice.setTitle("Get for " + String.init(self.dogsSort[indexPath.row].price) + "$", for: .normal)
cell.labelView.text = self.dogsSort[indexPath.row].name
cell.CityView.text = self.dogsSort[indexPath.row].description
cell.breedView.text = self.dogsSort[indexPath.row].breed
cell.ageView.text = self.dogsSort[indexPath.row].age
cell.weightView.text = self.dogsSort[indexPath.row].weight
}
return cell
}
And code which I am using currently, dummy code just to test the functionality, but it is not working...
dogsSort.remove(at: 0)
collectionView.deleteItems(at: [IndexPath(row: 0, section: 0)])
collectionView.reloadData()
If I understand you question this is what you have to do:
get your main array of dogs;
filter it:
filtered = dogsArray.filter({ $0.price > 30 })
If you want to filter the items based on a certain property, set again:
filtered = dogsArray.filter({$0.name == "something"})
In your CollectionView's delegate and data source methods you need to work with the filtered array, ie. (for the number of items in row):
filtered.count
I have the following problem.
In my project I have a table view with multiple sections and one row in every section. Inside row I have a collection view.
Collection view items count depending on section in which the collection is located.But I do not understand how to access section number when I call func numberOfItemsInSection for collection view.
Here is my code:
ViewController.swift
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
TableCell.swift
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//TODO ?????? How can i get here section of table view
}
Thanks!
Create an array in UITableViewCell subclass and use that array in collectionview datasource methods
class CustomCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource {
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
var collectionData = [String]()
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return collectionData.count
}
}
In tableView cellForRowAt method assign value to the array and reload colletion view
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell") as? CustomCell
cell?.collectionData = []//assign data here based on indexPath.section
cell?.collectionView.reloadData()
return cell!
}
Here you can use object oriented approach, in Your tableview cell create a variable tableSectionNumber. Like
class YourCell: UITableViewCell {
public var tableViewSectionNumber: Int = 0;
....
Now here in collectionView numberOfItemsInSection method, you can access it
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//TODO ?????? How can i get here section of table view
self.tableViewSectionNumber // its here
}
Now you can set this value in the cell in your ViewController, when you are populating the cell in TableView cellForRowItem method, Like
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! YourCell
cell.tableViewSectionNumber = indexPath.section // here you set the section number in cell
}
I'm trying to put a UICollectionView in a UITableViewCell, but I guess I'm doing wrong...
So here is my code :
PanierMenuCell is UITableViewCell
extension PanierMenuCell : UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return listProduit.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cellIdentifier = "PanierCollectionCell"
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath) as? PanierCollectionCell else {
fatalError("erreur de conversion !!")
}
cell.ONom.text = listProduit[indexPath.row].nomProduct
cell.OQtt.text = "x\(listProduit[indexPath.row].nbProduct)"
cell.OImage.image = UIImage(named: "test")
cell.backgroundColor = .gray
cell.layer.borderWidth = 1
cell.layer.borderColor = UIColor.lightGray.cgColor
cell.layer.cornerRadius = 5
return cell
}
}
Here is my class calling the UITableViewCell :
extension PanierVC : UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return listPanierProduct.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier = "PanierMenuCell"
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PanierMenuCell else {
fatalError("erreur de conversion !!")
}
let produit = listPanierProduct[indexPath.row].product as! Menu
let listProduit = produit.getListProducts()
cell.listProduit = listProduit
cell.OTotal.text = "Total: \(produit.prix)0€"
cell.ONomMenu.text = "Menu : \(produit.nom)"
cell.backgroundColor = .gray
return cell
}
So here is the problem :
When I'm using several cell with collectionView inside without scrolling the tableview, that's working well, the problem is when I need to scroll down the tableView (the tableview is so reloading the cell), that's causing an error : "Thread 1: Fatal error: Index out of range" in
cell.ONom.text = listProduit[indexPath.row].nomProduct
The item insides the UICollectionView are king of mixed together, I mean that a tableviewcell will take some items which are suppose to be in other tableviewcell, like if the cell.listproduit was mixed... Don't know how clear I was, but I can explain more if needed.
Any ideas on how I should solve this ?
Thank's a lot
You need to reload your UICollectionView after changing the data source. This will update the number of items in the collection view.
So after this line:
cell.listProduit = listProduit
Add this line (Assuming you have a property referencing your UICollectionView):
cell.collectionView.reloadData()
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])
/...
}
So I have a collectionView in a viewcontroller. I have a variable var user = User! which stores the current selected user (FYI I'm using Parse). I want to pass variable to the custom cell.
extension SentViewController : UICollectionViewDataSource
{
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int
{
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return cards.count
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(Storyboard.CellIdentifier, forIndexPath: indexPath) as! SentCardCollectionViewCell
cell.card = self.cards[indexPath.item]
cell.delegate = self
cell.user = user
return cell
}
}
Now, my problem is that when I pass the variable user to the variable user in custom collection view cell, I get an object that repeats 3 times. i.e.: the same variable gets passed over, but it is multiplied 3 times.
Any idea how to solve this? I have a feeling that it has something to do with the indexPath. Anyone have solutions?