CollectionView cell is selected when swiped on - ios

I have a collectionView showing cells. When I drag/touch/slide my finger on an item, if the touch ends on the item, the cell is selected (segues to the details screen).
Is there any way to limit cell selection (didSelectItemAt indexPath) to a simple tap? i.e it shouldn't select the cell if finger is dragged on an item and the touch ends on it.
Is this the default behavior?
I feel like it might be the cause of a cryptic issue with my custom navigation.
Thanks

Do add Following in your cellForItem
let tap = UITapGestureRecognizer(target: self, action: #selector(cellTapped(tapGestureRecognizer:)))
tap.numberOfTapsRequired = 1
cell.addGestureRecognizer(tap)
And add following function
#IBAction func cellTapped(tapGestureRecognizer: UITapGestureRecognizer)
{
//Do your required work.
}

You can use UITapGestureRecognizer, cause it will only respond on Tap gesture:
#objc func tapAction(_ sender: UITapGestureRecognizer) {
// TODO: - Action you need
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: <CellReuseId>, for: indexPath)
let tap = UITapGestureRecognizer(target: self, action: #selector(tapAction(_:)))
cell.contentView.addGestureRecognizer(tap)
return cell
}
But in this way didSelectItemAt will not work.

Related

Button add target function not called in CollectionView cell

I have a collection view where each of the cells has a delete button. I added the following code to cellForItemAt indexPath function.
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellTwo", for: indexPath) as! CustomCellTwo
cell.deleteButton.layer.setValue(indexPath.row, forKey: "index")
cell.deleteButton.addTarget(self, action: #selector(deleteCell), for: .touchUpInside)
Initially it looked as if it was working great. However, I found out that the add target function does not get called at the first tap if I scroll back and forth and then tap the delete button. If I tap again, it works as expected. Only the first tap does not work.
I have been trying to find a reason and a solution for several hours... Please help provide any ideas and advice.
Try to move buttons handling into CustomCellTwo implementation. Handle button event touchUpInside with #IBAction func. Now you can debug it with breakpoint set in this function's body.
Also add closure type variable to your CustomCellTwo to pass deleteCell calls into it. So it could also be checked with breakpoint.
Example:
class CustomCellTwo: UICollectionViewCell {
var onDelete: (() -> Void)?
#IBAction func onDeleteButtonTouch(_ sender: Any) {
onDelete?()
}
}
// in your UICollectionViewDataSource
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellTwo", for: indexPath) as! CustomCellTwo
cell.onDelete = {
self.deleteCell(indexPath)
}
}

UITapGestureRecognizer crashing app when clicking on collection view cell

I'm trying to allow user interaction in my collection view. I have decided to try to implement UITapGestureRecognizer to do this. I have tried adding a UITapGestureRecognizer to the collectionview itself and to the collectionview cell. Both ways crash the app. Here is how I am adding the UITapGestureRecognizer to the cell.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: "userCell", for: indexPath) as! UserCell
cell.userImage.sd_setImage(with: URL(string: self.user[indexPath.row].imagePath))
cell.nameLabel.text = self.user[indexPath.row].username
cell.userID = self.user[indexPath.row].userID
let singleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "segueToProfile:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
cell.addGestureRecognizer(singleTap)
return cell
}
When I tap on the cell I get a SIGABRT in the AppDelegate. The error message reads "terminating with uncaught exception of type NSException". What am I doing wrong. UITapGestureRecognizer.
This is my segueToProfile function:
func segueToProfile(gesture: UITapGestureRecognizer) {
// if(recognizer.state == UIGestureRecognizer.State.ended){
// print("myUIImageView has been tapped by the user.")
// }
print("hell world")
}
If you use didSelectItemAt method of collectionView your codebase look readable and maintainable.
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
currentViewController.performSegue(withIdentifier: "YourSegueName", sender: nil)
}
First, I would get rid of tapgesturerecognizer as didSelectItem should handle what you are trying to accomplish. That being said, in order for this to work you must:
Remove tapgesturerecognizer
Ensure that the collection view delegate is set to self.
e.g. <yourColletionViewName>.delegate = self
Above can be assigned at viewDidLoad()

Toggle image within uicollectionviewcell when clicked

I have a uicollectionview with a series of custom class cells that have a few textviews and a uibutton. With over 100 cells, I just want to toggle the uibutton image for each respective cell. The uibutton is a favorites button, and like most apps I just want to favorite and "un-favorite" different cells.
NOTE: I tried to add the gesture recognizer in the class directly, but for some reason the image changes, but it highlights multiple cells instead of the specific cell that was clicked
my code:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! SimpleExampleSubCell
cell.backgroundColor = UIColor.init(white: 0.10, alpha: 0.25)
cell.infoLine2TextVw.text = ""
cell.infoLine3TextVw.text = ""
if let heading_name = self.dict_dict_holder[indexPath.item]["Name"]{
cell.headerTextVw.text = heading_name
cell.infoLine1TextVw.text = self.dict_dict_holder[indexPath.item]["Phone"]
}
cell.bringSubview(toFront: cell.headerTextVw)
cell.favorite_button.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(AddFavorite(withSender:))))
return cell
}
#objc func AddFavorite(withSender sender:UIButton){
print("clicked")
//The line below fails each time I run it.
sender.setImage(newImage.png,.normal)
}
Replace
#objc func addFavorite(withSender sender:UIButton){
with
// not recommended use touchUpInside
#objc func addFavorite(_ sender:UITapGestureRecognizer){
let btn = sender.view! as! UIButton
}
OR better
cell.favorite_button.addTarget(self, action:#selector(addFavorite), for: .touchUpInside)
Don't Add tapgestures to buttons , as they they have their own targets like touchUpInside or touchUpOutside and many more
table cells are reused you need to nil them inside cellForRowAt or give an else
if someCondition {
cell.favorite_button.setImage(newImage1.png,.normal)
else {
cell.favorite_button.setImage(newImage2.png,.normal)
}
you have to set the default image (plus everything you want to reset) for each cell in the prepareForReuse() method so it clears up the reused content

Add Pan Gesture to UICollectionView Cell - IOS/Swift

I have an UICollectionView and I want to add pan gesture to its Cells/Items. When I add the gesture in usual way UICollectionView is not getting scrolled.
This is how I add the gesture
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell:UICollectionViewCell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(CaptureViewController.pagesCollectionViewItemPanEvent(_:)))
cell.addGestureRecognizer(panGesture)
return cell;
}
Is there something wrong here? Can someone please tell me a way to get my work done. Any help would be highly appreciated.
You should add the gesture to the collection view and not to the cell itself.
Something like...
let panGesture = UIPanGestureRecognizer(target: self, action: "handlePanGesture:")
collectionView.addGestureRecognizer(panGesture)
func handlePanGesture(gesture: UIPanGestureRecognizer) {
let locationInView = gesture.locationInView(collectionView)
...
}
Just a proposal, I didn't test it:
Create a custom cell:
class PanCell: UICollectionViewCell {
override func awakeFromNib() {
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.pagesCollectionViewItemPanEvent(_:)))
self.addGestureRecognizer(panGesture)
}
}
and you can use the delegation to inform CaptureViewController.

Add a tap event to CollectionViewCell while passing Cell data

I want to add a tap event to my CollectionViewCell and to pass there my cell with the data it has. How can I achieve this?
Should this event be handled by my ViewController or by CollectionViewCell?
My ViewController:
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as! CollectionViewCell
cell.imgImage.image = imageArray[indexPath.row]
cell.url = "xhini"
return cell
}
My CollectionViewCell:
class CollectionViewCell: UICollectionViewCell {
#IBOutlet weak var imgImage: UIImageView!
var url: String = "url"
}
Implement UICollectionViewDelegate and then you can use following method in the ViewController to react to selecting a cell:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let image = imageArray[indexPath.row]
// do stuff with image, or with other data that you need
}
Don't forget to set the delegate where you set a data source:
collectionView.dataSource = self
// add this line:
collectionView.delegate = self
UPDATE
Or if you are using a storyboards, you want to set it using storyboards the same way as you set a dataSource for the dataSource of the tableView:
UPDATE 2
Your tap gesture recognizer cancels event for the collection view, so to deal with this, just uncomment the line tap.cancelsTouchesInView = false, and it will work:
//Looks for single or multiple taps.
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
//Uncomment the line below if you want the tap not not interfere and cancel other interactions.
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
I saw your code which you shared in the above answer by #Milan and figured out the reason.
You have added a tap gesture on viewDidLoad of ViewController :
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
This makes the UICollectionView's didSelectItemAt not getting called.
So comment this code and it should work.
For this gesture, you have to find another approach

Resources