UICollectionView didSelectedItemAt : first click on cell doesn't work - ios

Like written in the title, the didSelectedItemAt is bugging, but that's a little more complicated than in the title, I explain:
I try to code an application which is listing some stuffs. So I've got a ViewController with inside a TableView and a CollectionView. At the beginning the tableview's hidden is on false and the collectionview's one is on true. I've got a button on the navigation bar to switch CollectionView / TableView hidden true/false (I hope I'll be understandable with my bad English !). So the didSelectedRowAt is working well, but the didSelectedItemAt isn't. When I first click on a cell, nothing happen (on the screen at least), but the second click is working..... With the indexpath of the first click... I can't figure out why that's happening.
Does anyone know why?
Here is the some code of the app:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
print (dogs[indexPath.row].name)
let vc = storyboard?.instantiateViewController(withIdentifier: "DogDetailsView") as? DogDetailsView
vc?.nameSend = dogs[indexPath.row].name
vc?.infoSend = dogs[indexPath.row].info
self.navigationController?.pushViewController(vc!, animated: true)
}
Thank you for helping

You are using wrong delegate method. Use following
- (void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath;
The reason behind your didDeselect is working after the second tap is, you have turned on allowMultilpleSelection and whenever you tap first that cell its get selected, but you didn't implemented the correct delegate to hear that. when you tap once more, that cell is now deselected. That's why you are getting the callback in implemented method in such way.

Related

UICollectionViewController + diffableDataSource - cell gets unhighlighted while your finger is still on it

If I am using UICollectionViewController with diffableDataSource and tapping on cell - it highlights, but then gets unhighlighted while I'm still holding finger on it.
If to use UIViewController + collectionView with diffableDataSource - then everything working as intended, and cell keeps highlighted until I release finger from it. The same if to use UICollectionViewController with standard dataSource - everything working good.
Has anyone noticed this problem as well? Any advice or thoughts would be appreciated, maybe I'm just missing something, but for now it feels more like a bug from Apple side
You can see the example here:
https://github.com/ashishbl86/MockAppStore/blob/0ea8e74a4823c8c80bd7e8d5c6a9514958fbe459/MockAppStore/CollectionViewController.swift
Just add to CollectionViewController.swift file these methods:
override func collectionView(_ collectionView: UICollectionView, didHighlightItemAt indexPath: IndexPath) {
print("cell highlighted")
}
override func collectionView(_ collectionView: UICollectionView, didUnhighlightItemAt indexPath: IndexPath) {
print("cell unhighlighted")
}
and you'll see that "cell unhighlighted" is printed while your finger is still on a cell
okay as it turned out we need to set
installsStandardGestureForInteractiveMovement = false
this variable installs a standard gesture recogniser for UICollectionViewController to drive the reordering process.
It is set to true by default, but in order to make things work the collectionView dataSource must declare its support for reordering items by implementing the appropriate methods.
In old good dataSource methods moveItemAt are marked as optional, while in diffableDataSource it is not declared as optional any more, which is the reason for this variable to cause the behaviour described in the issue above.
More info about this variable available in docs:
https://developer.apple.com/documentation/uikit/uicollectionviewcontroller/1623979-installsstandardgestureforintera

collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath is not executed

Here is my image of collectionViewCell .
I have collectionView inside tableViewCell and I have a button inside collectionViewCell which is working perfectly as my wish. But What is troubling me is the function didSelectItemAt is not being called .
I tried with
mycollectionview.isUserInteractionEnabled = true
mycollectionview.allowsSelection = true
but still not working . Is the button inside collectionViewCell is the cause behind it as I read somewhere . If its is so how can I fix the issue .
Please confirm that you have set the delegate for the UICollectionView to your ViewController not the TableViewCell. If you have set the Delegate to UITableViewCell, then your didSelectItemAt will be called inside the TableViewCell's class
try this code in swift 4
cell.btnCart.addTarget(self, action: #selector(btnCartAction), for: .touchUpInside)
and handle the action
#objc func btnCartAction(sender:UIButton) {
//write your code here
}
Check your all views which are placed on cell.If they have user interaction enabled and if user interaction enabled then what is the size of that item. It looks like some view is covering the whole cell that's why did select item does not get called.
Please check Your Button size ,tableView selection (single selection or Multiple), check tableView user Interaction is enable, also check datasource or delegate is connected

didSelectItemAt for UICollectionView is only calling on double touch

I'm facing a weird issue in UICollectionView using iOS11 emulator. In my project i have a UICollectionView with UIImageView as cells and I've created segue as Triggered Segues for cells by dragging it to a view controller. It was working great but know the segue is not performing so i decided to remove the segue from cells Triggered Segues and I created a segue from my view controller to the destination view controller and performed segue from code
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "PhotoCell", for: indexPath) as! PhotoCell
if let url = URL(string: "\(StringResources.serverAddress)/Content/images/Files/Thumb/\(photos[indexPath.row])") {
cell.image.downloadFrom(url: url)
}
return cell
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("clicked")
performSegue(withIdentifier: "PhotoSegue", sender: collectionView.cellForItem(at: indexPath))
}
but it's not working either and there is no clicked printed in console. I've checked cell and UIImageView user interaction also UICollectionView delegate is ok. How can i fix it?
edit: I've found the problem. It's only calling when I'm double clicking on cell
There are some things that you could check and once all of them are in order it should work:
Check that your UICollectionView has both delegate and dataSource set.
Check that your UIImageView userInteractionEnabled property is set to false.
According to documentation:
Image views ignore user events by default. Normally, you use image views only to present visual content in your interface. If you want an image view to handle user interactions as well, change the value of its isUserInteractionEnabled property to true. After doing that, you can attach gesture recognizers or use any other event handling techniques to respond to touch events or other user-initiated events.
Check that both UICollectionView and parent have. userInteractionEnabled property is set to true.
Check that there are no other UIGestureRecognizers catching your touch event.
Check that there are no network requests freezing your UI.
Considering the information that you provided, I would try to remove the UIImageView from the cell and make sure that the cell touch is working before adding more elements.
the problem is that I was adding a UITapGestureRecognizer to dismiss the keyboard and that was catching touch events.
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tap)
}
The issue could be due to the fact that collection views have a didSelectItemAt method as well as a didDeselectItemAt method which alternate per click. This could explain why it only works on a double click (one click calls didSelect, the next calls didDeselect).
A quick (but not elegant) solution could be to implement your didDeselectItemAt and just use it to call the didSelectItemAt

DidSelectItemAtIndexPath not working with collectionview

So I have been struggling with this for a while now. I have a UICollectionView that I am using as a menu. The cells are the options to switch to another page. The menu functions exactly how it should except that when you press a cell, say cell 0, it should pop to the next view. What I am finding is that the cell is registering the touch but when I try and determine which cell was pressed is when it falls apart. I have tried debugging it and to me it looks like indexPath has no value! I am using the didSelectItemAtIndexPath function, no it is not didDeselect (I checked that already from my searches on how to fix this). I will post the code but this one has really stumped me. Any help would be greatly appreciated!
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
NSLog("Pressed Cell")
if(indexPath == 0)
{
self.navigationController?.popToViewController(profileViewController, animated: true)
}
}
NSIndexPath comprises both a section and an item, which you can access as indexPath.item and indexPath.section. Assuming you have only one section (so its value is irrelevant), you can change your code to:
func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath)
{
NSLog("Pressed Cell")
if(indexPath.item == 0)
{
self.navigationController?.popToViewController(profileViewController, animated: true)
}
}
I am sure normally call the delegate method but if have add any Gesture to the view. Make sure before you add your gesture recognizers to you're view, make sure the boolean property "cancelTouchesInView" is set to false. This could be because the gesture is recognized so it ignores passing touches to the view causing the cell selection method not to be called. Link to property.

detecting when an iOS UICollectionCell is going off screen

I'm having a UICollectionView that holds pictures as elements in its datastore.
I want to load a high resolution pic into the element only when its corresponding UICollectionViewCell is currently showing on screen. Later, when the UICollectionViewCell goes off screen, I want to return the element's UIImage into the low resolution version.
My question is, how can I detect when a UICollectionViewCell is going off screen?
(I tried using the prepareForReuse method but I can't predict when it will be called).
I'm currently using a piece of code that sits in scrollViewDidScroll, and every time that the view scrolls I'm checking the self.collectionView.visibleCells to see which cells has scrolled off screen.
It seems a bit of an overhead and I wonder if there is a method called on the UICollectionViewCell itself whenever it is being scrolled of screen ?
The collectionView:didEndDisplayingCell:forItemAtIndexPath: method on UICollectionViewDelegate should do what you want.
From Documentation. collectionView:didEndDisplayingCell is called right after it finishes displaying, not when it goes off screen
Use this method to detect when a cell is removed from a collection view, as opposed to monitoring the view itself to see when it disappears
collectionView:didEndDisplayingCell:forItemAtIndexPath: is the correct method to detect when a cell has gone from screen.
Meanwhile, I think it's more correct not to perform cleanup in collectionView:didEndDisplayingCell:forItemAtIndexPath: but to tell your cell to perform cleanup itself:
func collectionView(_ collectionView: UICollectionView,
didEndDisplaying cell: UICollectionViewCell,
forItemAt indexPath: IndexPath) {
cell.prepareForReuse()
}
With this approach your UICollectionViewDelegate doesn't have to know any implementation details of your UICollectionViewCell subclass. In the cell we'll override prepareForReuse method:
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = lowResolutionImage
highResolutionImage = nil
}

Resources