I have a simple collection view in my app, and I use the delegate to get notified when a cell was tapped, so I implement didSelectItemAtIndexPath: method. In Swift 2 this method's signature looked like this:
#objc func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
After running thru migration process this signature changed to this:
#objc func collectionView(collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
The compiler was happy and I moved on, but now this method doesn't get triggered when I tap any cell. I found a way to fix it:
#objc(collectionView:didSelectItemAtIndexPath:) func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
Obviously, the problem was in the first parameter name, but I still don't understand why it doesn't work without specifying obj-c selector explicitly.
no need to write #objc,
Here is a working code,
extension YourViewController:UICollectionViewDelegate{
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("didSelect")
}
}
add delegate in viewdidload also add uicollectionviewdelegae,uicollectionviewdatasource also in storyboard,
this helps me.
Related
This maybe a duplicate post. But I haven't found any solution in the answers given in previous questions.
Basic checks from my side that I have done.
No errors on the constraint that I have put on CollectionView and CollectionViewCell.
When numberofitemsinsection is called, it always returns more than 0.
Reusable identifier is tagged for both CollectionView and CollectionViewCell
All links for ui objects are at place.
CollectionViewCell size is set as default.
Some more information on my code.
class StickerGridCollectionViewController: UICollectionViewController{
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return stickerPackList.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
/*some code*/
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
/*some code*/
}
}
I checked all the answers here, but didn't find my answer yet.
Any clue why I might be getting this issue?
Update
When I open debug view hierarchy, I find out that collectionview is taking correct area, but views which were supposed to be inside collectionview are flowing outside and acting abnormally.
Moreover I see UICollectionView inside UiCollectionView.
Any reason, why this abnormal behaviour might occur?
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 am converting my project to Swift 3 in Xcode 8.1 and one of my collection view functions is returning a warning message indicating that the footprint has changed. The code is
func collectionView(_ collectionView: UICollectionView, cellForItemAtIndexPath indexPath: IndexPath) -> UICollectionViewCell {
and the warning is
Instance method CollectionView(:CellForItemAtIndexPath:) nearly matches optional requirement collectionView(:canFocusItemAt:) of protocol UICollectionViewDelegate
I believe the warning is a red herring here. I looked up the API reference https://developer.apple.com/reference/uikit/uicollectionview/1618088-cellforitem and I see
func cellForItem(at indexPath: IndexPath) -> UICollectionViewCell?
However, I am unable to find a declaration along these lines which won't result in a compiler error with a red dot.
edit:
After the answer below I added the datasource to my ViewController class as follows:
class MyController: UIViewController,
UICollectionViewDelegateFlowLayout,
UICollectionViewDataSource,
then in ViewDidLoad() I added this myCollectionView.dataSource = self.
I now have this
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
This View Controller is entirely constructed in code and had not implemented datasource although there was code for numberOfSectionsInCollectionView which produced a compiler red dot after the datasource was added. This was updated to
func numberOfSections(in collectionView: UICollectionView) -> Int {
I believe the warning is a red herring here
Well, it isn't. Typically the way to treat the compiler is with respect; it usually knows considerably more than you do. Your https://developer.apple.com/reference/uikit/uicollectionview/1618088-cellforitem is the red herring.
This is the function you want:
https://developer.apple.com/reference/uikit/uicollectionviewdatasource/1618029-collectionview
As you can see, the signature is:
func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
... which is subtly different from what you wrote originally.
Another thing to watch out for is that you must make this declaration inside a class declaration that explicitly adopts UICollectionViewDataSource. The only exception is if this is a UICollectionViewController, in which case it already adopts UICollectionViewDataSource — and in that case, the compiler will tell you to add override to your declaration (and you should obey).
Hi I am somewhat new to iOS and swift. I recently switched to swift 2.3 and now I am getting this error
Use of undeclared type 'IndexPath'
for this method
override func collectionView(collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
Any Ideas??
The function parameter should be NSIndexPath not IndexPath. Xcode 8+ uses the documentation and code completion for Swift 3.0.
Swift 2.3 syntax:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
Swift 3.0 syntax:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath)
Yup! It's wrong in the Apple documentation. Not sure why they don't just fix it
I have implemented a UICollectionView that holds list of UIImageView objects.
I want the user to be taken to YouTube with specific URL when he touched an image.
But I don't know how to add touch listener for each UICollectionViewCell:
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell: PhotoCell = collectionView.dequeueReusableCellWithReuseIdentifier("PhotoCell", forIndexPath: indexPath) as PhotoCell
cell.loadImage(thumbnailFileURLs[indexPath.row], originalImagePath: originalFileURLs[indexPath.row])
return cell
}
My PhotoCell class has a member variable that holds the URL to youtube.
For each PhotoCell object, when pressed, I want my app to send the user to youtube.com website or APP (if installed)
You should implement UICollectionViewDelegate protocol method collectionView(_:didSelectItemAtIndexPath:). When you press one of your collection view cells this method get called. Here is sample implementation
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let url = thumbnailFileURLS[indexPath.item]
if UIApplication.sharedApplication().canOpenURL(url) {
UIApplication.sharedApplication().openURL(url)
}
}
By the way I don't know where you get url. So I improvised a bit :)
Swift 5
didSelectItemAtIndexPath has been renamed to didSelectItemAt in Swift 5
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
//Do your logic here
}