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.
Related
My UICollectionViewCell has a text field, when I click the cell it lets me edit the text field but the didSelectItemAt function of the UICollectionViewDelegate is not being called. How can I overcome this?
class LetterCell: UICollectionViewCell {
#IBOutlet weak var singleLetterTextField: UITextField!
#IBAction func textDidChange(_ sender: Any) {
if ((singleLetterTextField.text?.count)! > 1) {
singleLetterTextField.text = String((singleLetterTextField.text?.last)!)
}
}
}
This is the collectionView function
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LetterCell", for: indexPath) as! LetterCell
cell.singleLetterTextField.text = data[row][column]
increaseRowColumn()
return cell
}
And I already set the delegate and the data source to the controller.
Considering you need your text field to be editable.
didSelect will work if cell is touched outside of textfield.
It is not unlikely so if you want to recognize didSelect along with editing, you will need to do the calculation in textField didBeginEditing. A basic hack will be to set index path's values as tag or other property of your textfield, in cellForItemAt (check eg.). You can create a custom text field as well.
Here is update to your cellForItemAt:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
var cell = collectionView.dequeueReusableCell(withReuseIdentifier: "LetterCell", for: indexPath) as! LetterCell
cell.singleLetterTextField.text = data[row][column]
cell.singleLetterTextField.tag = indexPath.row//then you can use this tag to form indexPath and with that you can retrieve cell (if it's still visible)
increaseRowColumn()
return cell
}
First
singleLetterTextField.isUserInteractionEnabled = false
Then in didSelectItemAt
cell.singleLetterTextField.becomeFirstResponder()
I have an odd problem with my UICollectionView. When I select the first cell in my Collection View the last cell is highlighted but does not show up in the array of selected index paths. Why is this happening?
Here is the code I am using to select and deselect the cells?
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// handle tap events
print("You selected cell #\(indexPath.item)!")
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderWidth = highlightedCellBorderWidth
cell?.layer.borderColor = UIColor.yellow.cgColor
selectedImages.append(imageArray[indexPath.item])
print(selectedImages)
print(collectionView.indexPathsForSelectedItems)
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath)
cell?.layer.borderWidth = 0
let index = selectedImages.index(of: imageArray[indexPath.item])
selectedImages.remove(at: index!)
print(selectedImages)
print(collectionView.indexPathsForSelectedItems)
}
You don't show how your cell is initialized, but...
collectionView(_:didDeselectItemAt:) is only called when the user successfully deselects an item. It does not get called if you deselect an item programmatically. If you are not resetting your layer's borderWidth when initializing a cell, the non-zero width will carry forward when the cell is reused by the collection view.
I found this link on S.O. which was helpful. To solve the problem I simply added the following code to my func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {}.
Code...
if collectionView.indexPathsForSelectedItems?.contains(indexPath) == true {
print("This cell is selected \(indexPath.item)")
cell?.layer.borderWidth = 3
cell?.layer.borderColor = UIColor.yellow.cgColor
}else{
cell?.layer.borderWidth = 0
}
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?
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.
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