I have more than one collectionView in a ViewController. The cell of those collectionViews has the same format.. so I'm reusing them. So my question is: How to identify in the method
func collectionView(_ collectionView: UICollectionView,
didSelectItemAt indexPath: IndexPath)
I don't want to do a couple of if's
I've found this solution everywhere, but really don't like it. Here is the code
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
if let aCell = cell as? ItemCollectionViewCell{
aCell.setupCell(with: self.items[indexPath.item])
}
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if collectionView == self.colletionViewTwo{
// goto viewController1
}else if collectionView == self.colletionViewOne{
// goto viewController2
}
}
Create two classes that implement the collection view delegate and data source and use one of each. So you'll have these two extra objects in your current view controller.
Seeing your code now, the above is probably too heavy. Alternatively, add a dictionary in which you store the collection view as key and a selector as value. This is extensible as you say you want.
To be honest, what's your issue an if (or switch) statement like you have now?
Related
I have looked through google and stack overflow and I was not able to find an answer. I have a UICollectionView and would like to take the user to another view upon the cell being clicked. But before doing so I would like to click the cell on the simulator and have the label's name printed in the console so I can from there figure out how to write the performSegue method. I am having issues with the didSelectItemAt function.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let clothesCell = collectionView.dequeueReusableCell(withReuseIdentifier: "clothesCell", for: indexPath) as! closetCollectionViewCell
clothesCell.clothingName.text = shirtStyle[indexPath.item]
clothesCell.clothingColor.text = shirtColor[indexPath.item]
clothesCell.clothingSize.text = "\(sizes[indexPath.item])"
return clothesCell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print(indexPath.item.clothingName)
}
Use this for print in didselectItem for selected items
print(shirtStyle[indexPath.item])
You need to get the cell that was clicked at indexPath like this:
let cell = collectionView.cellForItem(at:indexPath) as! closetCollectionViewCell
Then just get the values from the cell variables and print.
I am creating a project where I have a lot of options for user to select among different plans.
So I created a UITableViewCell, put UICollectionView inside with one UICollectionViewCell as one plan.
Now user can select only one plan out of all.
Let's say the user selects the second plan, I need to update the price on a button which is in UITableViewCell.
I know we can reload tableCell and update. But is there any other way to do except reloading UITableViewCell
Let me know the best way to do that except reloading whole tableviewcell
In didselect method of Uicollectionview, get the tableviewcell of price displaying and update the button.
CollectionView didSelectItem method
{
NSIndexPath *indexpathoftableviewcell = [NSIndexPath indexpathForRow:1 inSection:0];
UITableViewCell *priceCell = [tableView cellForRowAtIndexPath: indexpathoftableviewcell];
UIButton *priceBtn = (UIButton*)[priceCell viewWithTag:tagOfBtn];
[priceBtn setTitle:#"43432" forControlState:UIControlStateNormal];
}
Assuming your UITableViewCell loads the UICollectionView inside it, so the obvious choice for UICollectionView's DataSource and Delegate should be your UICollectionViewCell.
So in your TableView Cell you can simply access the label that you need to update with price as shown below
extension MyTableViewCell : UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 100
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let someCell : MyCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "your_identifier", for: indexPath) as! MyCollectionViewCell
return someCell
}
}
extension MyTableViewCell : UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath) as! MyCollectionViewCell
self.priceLabel.text = "\(cell.value)"
}
}
here I am assuming that your CollectionViewCell is a custom cell and has a property named value where it store the price of plan
Accommodate the Plans (UICollectionView) & Price (UILabel or UIButton) in the UITableViewCell rather than making it as separate cells
Here is the reason behind it.
Both Price and Plans are tightly coupled. It means, When you change plan the respective price should come and this requirement may grow in future like adding some more views. If you accommodate the entire part in one UITableViewCell, it will become very easy. This way you can manage your design future proof.
regarding the question, the price is just like one more IBOutlet in the CustomTableViewCell. Just update the price in
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {}
I need to get the next cell inside cellForItem within a collection view so that I can update a view object. When I try the following below it doesn't work. I've also tried indexPathForVisibleItems passing in indexPath.row + 1 and the produces an index out of range error.
let index = IndexPath(row: indexPath.row + 1, section: indexPath.section)
if let nextCell = collectionView.cellForItem(at: index) as! MKRCell {
nextCell.setupWaitView(time: timeToWait)
nextCell.waitViewHeightConstraint.constant = 80
nextCell.waitView.alpha = 1
nextCell.waitView.isHidden = false
}
Is this possible to achieve or will I need to do this via another way?
Thanks
No, it is not possible to get the cell object before initialization in cellForItemAt but here
you can receive the call before displaying the cell from UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView,willDisplay cell: UICollectionViewCell,forItemAt indexPath: IndexPath) {
if let myCell = cell as? MKRCell {
}
}
AND
If you want to set up the cell you have to setup view in the UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
}
You should update the cell in:
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
Remember to modify only the cell you'll be returning from this method. Other cells might not have exist at that moment.
Alternatively you can keep a weak reference to the cell and update it when needed.
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.
I want to set a variable to different string when a certain CollectionView cell is tapped. So cell1 is tapped then var cellTapped = "cell1", cell 2 is tapped then var cellTapped = "cell2" and so on. It was suggested that I
"create a custom cell and hold the value as property and read this
value on didSelectCell()"
but I'm not sure how to do this (newbie).
(Swift 3)
You need to set UICollectionViewDelegate to your ViewController and then implement didSelectItemAt IndexPath that gets called when a cell is tapped.
Something like this:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
cellTapped = "cell" + String(indexPath.row)
}
You could also have an array of Strings and index into the array based on the indexPath.row:
let cellStringValues = ["cell1", "cell2", "cell3", ... , "celln"]
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
cellTapped = cellStringValues[indexPath.row]
}
Setup your view controller to be the delegate of the UICollectionView. Your view controller should inherit from UICollectionViewDelegate. Then in the viewDidLoad() for the VC set the delegate variable for the UICollectionView to be the ViewController. To catch selection events override the following UICollectionViewDelegate function.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
cellTapped = "cell\(indexPath.row)"
}
Check out https://www.raywenderlich.com/136159/uicollectionview-tutorial-getting-started for more details on working with collection views