I use this code to show a collection of images, which are scrollable. However, I would like to add a property to make it possible to identify each cell or image in this case. I want a property to every cell that can hold a string.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PalletsCollectionViewCell", for: indexPath) as! PalletsCollectionViewCell
cell.imgImage.image = imageArray[indexPath.row];
return cell;
}
Haven't found anything while reading the swift documentation.
What I want to do is to add events to the cells. If the user touches a cell, a function will be called. This function performs an API request with the property value as parameter.
Related
In my view controllers, a lot of my cellForItemAt methods have computations in them. In the following example, I get the amount, image, and balanceAtDate and pass them into my view:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SummaryCell.cellId, for: indexPath) as! SummaryCell
let amount = filteredTransactions[indexPath.row].transactionAmount
let image = UIImage(named: filteredTransactions[indexPath.item].transactionCategory!.categoryName)
let balanceAtDate: Double = realm.objects(Transaction.self).filter("transactionDate <= %#", transactionResults[indexPath.item].transactionDate).sum(ofProperty: "transactionAmount")
cell.configure(with: image, and: amount, and: balanceAtDate)
return cell
}
It has come to my attention that I shouldn't make any computations or calculations in cellForItemAt because it is called for every cell and it will slow down the application.
I create 3 constants: amount, image, and balanceAtDate. Do I need to put all three somewhere else, or just the balanceAtDate?
Where, then, do I put a computation that requires the indexPath.item to get something like the balanceAtDate?
so I am trying to change the background color of the collection view cell that is clicked, however, when I call the CollectionView.reloadData() method the backgrounds don't change. I am thinking that reloading the data only checks for adding and deleting cells, but does not actually call the configure function for each cell again. I was wondering how I can reconfigure these cells so that the background color can change for the selected cell. Thanks for the help in advance!
This is the method that I call:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
...
bagCollectionView.reloadData()
}
Instead of calling reloadData, you can try:
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.backgroundColor = yourColor
}
Even though you do your logic in did select by finding a cell or implement logic in didSelectItemAt and didDeSelectItemAt, I suggest you should store the Index. Due to reusability of cell, there is chance that selected cell do not show color on scroll or if you have large number or records.
So save index in array(for multiple selections) or a single variable(single selection) and manage logic for the same.
For example:
cell.backgroundColor = selectedIndex == indexPath.item ? .red : .yellow
I am using UICollectionFlowLayout to establish minimumLineSpacing between collectionItems, I am trying to find a way to set the spacing to zero for some cells so there is no spacing, i.e they appear to be 'merged' while leaving others with their spaces intact, is it possible to make alterations in the cellForItemAt method for example to achieve this?
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "customColCell", for: indexPath) as! customColCell
if indexPath.row == 5 {
self.minimumLineSpacing = 100 // -- this does not result in an individual change...
}
cell.textLabel.text = indexPath.row.description
return cell
}
is it possible to make alterations in the cellForItemAt method for example to achieve this
No. What you're asking to do is not how a UICollectionViewFlowLayout behaves by default. You will need to write a collection view layout subclass.
There are a few posts on UICollectionViews and as a general concept I understand UICollectionViews are similar to how TableViews are implemented. There are a few posts on this topic already.
How to make a simple collection view with Swift
I'm using a UICollectionView to layout 8 cells for essentially decorative purposes...just as a container to hold a few images for a page. The images aren't meant to be interactive eg. a shopping cart.
My question is whether I need to implement the function below (and other similar functions) if i'm laying out my cells on the storyboard.
// tell the collection view how many cells to make
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
I have 8 cells within a UICollectionView that i have configured on the storyboard (this collection view is a view on a UIViewController) and each UICollectionViewCell has an image view with in. I have laid this all out on the storyboard.
I also don't want to put an image in each cell. Just a certain number of cels eg. cells 2,3,5 and 8.
So what I was going to do is create a class that extends UIControllerViewCell and create an IBOutlet for the image view and then in the interface builder reference the custom cell class.
And I think - but could do with some advice - then all I need to do is use the function below and because I only want to populate certain cells I can use an if statement for index path when it's 2,3,5 and 8:
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if(indexPath == 2 || 3 || 5|| 8)
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! MyCollectionViewCell
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.image = self.items[indexPath.item]
return cell
}
}
Thanks.
cellForItemAt must return value (which is UICollectionViewCell instance in this case), but you are free to set image of certain cells to nil (AKA no image)
eg:
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyCollectionViewCell
if([2,3,5,8].contains(indexPath.row))
{
// Use the outlet in our custom class to get a reference to the UIImageView in the cell
cell.myImageView.image = self.items[indexPath.row]
} else {
cell.myImageView.image = nil
}
return cell
}
Sounds like you are asking about a static UICollectionViewController which is not possible. You will make a single prototype cell in the storyboard and link the IBOutlets with the desired class. You will also need to implement the data source and delegate methods for UICollectionView. Just hide the image where you don't want to show it based on the index.
I am using custom share extension in my application.When i am using collection view delegate method in my share viewcontroller class it gives me the bad EXC_BAD_INSTRUCTION on making the uicollectionview cell object.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MediaCollectionViewCell
return cell
}
I got the answer of my question in my case i do not set the identifier of view controller in storyboard that it the reason for bad access.