didSelectItemAt for UICollectionView is only calling on double touch - ios

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

Related

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

UIButton behavior changes if collectionView moveItemAt is overridden

I have a collection view controller. One of collection view's cells contains a button with Touch Down and Touch Up Inside.
Strictly speaking, the button is in the view of view controller which is a subview of the collection view cell.
When the button is pressed the Touch Down is fired and when the button is released the Touch Up Inside is fired. Until the button is not released the button is grayed and the Touch Up Inside is not fired.
This is exactly the behaviour I need.
Now, I have implemented these two methods to support reordering collection view's cells:
func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool
func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
If the second method is implemented (both if canMoveItemAt returns true or false), the button behavior changes:
as soon as the button is pressed, fires the Touch Down event and immediately after that, it also fires the Touch Up Inside event.
the button is grayed when pressed and immediately gets back to its normal state like it has been released
when the button is released, nothing happens
My suspect is that events propagate from button to the collection view controller, but I have no idea how to prevent it.
Can anyone help me?
Tks
You are right, but if you stop it, you stop reordering as well. Basically you need to choose what do you need: button to be pressed or cell to be dragged. Perhaps you can achive expected behaviour utilising Collection cell capabilities, instead of button. You can easily change button states, if you need button to represent that cell is being dragged.

Buttons in a UICollectionView don't receive touch events

I've been looking around for a while now but can't seem to work out how to stop the collection view cells from consuming the touch events.
I need the touch events to be passed down into the respective cells so that the buttons within the cells can be pressed. I was thinking i might need to work out how to disable the UICollectionView's didSelectCellAtIndexFunction?
I've also seen this as a potential solution: collectionView.cancelsTouchesInView = false
Also this link might help someone answer my question: How to add tap gesture to UICollectionView , while maintaining cell selection?
Thanks in advance!
Edit:
Also I should add: my buttons are added to a view that is in turn added to the cell's contentView. My code is done all programatically and so I am not using interface Builder at all.
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
return false // all cell items you do not want to be selectable
}
Assuming all buttons are connected to the same selector, you need a way to differentiate which cell's button has been clicked. One of the ways for finding out the button's cell's index is:
func buttonPressed(button: UIButton) {
let touchPoint = collectionView.convertPoint(.zero, fromView: button)
if let indexPath = collectionView.indexPathForItemAtPoint(touchPoint) {
// now you know indexPath. You can get data or cell from here.
}
}
Try on your cell.
self.contentView.isUserInteractionEnabled = false

Handling button interaction of a dequeueReusableCell in iOS Swift

I am making an iOS app that relies on a table view. In each cell of the table view, there are 4 buttons aligned on the bottom. I have a cell class that is pretty standard and a feedController to handle the table and setting all the items of the cell.
Everything works fine on it but I can not figure out how to handle the button clicks within the cell. I can hard code it into my cell class, but then every 3 cells has the same interaction. Is there a way to pass the button click function from the cell class into the controller? I have tried checking the state from the controller and that has not worked.
Can you add a gesture recognizer as you're doing your cellForItemAtIndexPath? So I had something similar with a collection view, and what I did was as it within:
func collectionView(collectionView: UICollectionView!, cellForItemAtIndexPath indexPath: NSIndexPath!) -> UICollectionViewCell!
{
var cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as MyCollectionView
...
I would add a gesture recognizer to each cell
i.e.
cell.addGestureRecognizer(UITapGestureRecognizer(target: self, action:Selector("tapAction:")))
And then something like:
func tapAction(recognizer: UITapGestureRecognizer) {
...
}
so recognizer ends up being the specific item tapped, and I could take action accordingly (in my case, I had my datasource of items and I would find the item in an array by casting recognizer to a cell, finding the appropriate subview, and update values on it)
I would add code block properties to your cell class which the table can assign to deal with each button. In your cell, code each button handler to call the appropriate block, or pass an index for the button used in a single block.
See my answer here which has an example, but for a switch.
How can I get index path of cell on switch change event in section based table view
If after a few cells you get the same interaction, it's possibly because you're dequeueing a reusable cell, and you're getting the same cell.
Make sure to set your .setTarget() call for your buttons in your tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) data source every time the cell is dequeued. It would help if you shared how you're handling dequeuing to see if this is your issue.

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.

Resources