I have a table cell view with 4 UIButtons:
Buttons have Touch Up Inside event
#IBAction func increasDealRatingAction(sender:UIButton) {
let buttonPosition = sender.convertPoint(CGPointZero, toView: self.tableView)
if let indexPath = self.tableView.indexPathForRowAtPoint(buttonPosition) {
...
}
}
And i have edit actions for each cell:
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
...
return [addToWishListAction, addToPurchasesAction, deleteAction]
}
The issue, when you swipe left to show “add to wish list”, ”delete” actions from position of star buttons, click event handled too or swipe action doesn't detect while you swipe on button area.
Add a swipe gesture recognizer to the buttons
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: Selector("handleSwipes:")) // nil for selector is also possible
swipeGestureRecognizer.direction = .Left // Add this if you want only one direction
dealRatingButton.addGestureRecognizer(swipeGestureRecognizer)
// Add three star buttons
and impletment gestureRecognizer(_:shouldReceiveTouch:) to return false.
Related
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.
I would like my tableView to only react to double taps and not at all to single taps. I am currently using the following code:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(singleTap))
tapGesture.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGesture)
let doubleTapGesture = UITapGestureRecognizer()
doubleTapGesture.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTapGesture)
tapGesture.require(toFail: doubleTapGesture)
// implement what to do
if userInfo[indexPath.row].identifier == "username" {
editUsername()
}
}
func singleTap() {
// DO NOTHING
}
So basically I have been trying to "redirect" the single tap to a function that does nothing. However, I find that (in the simulator), the tableView sometimes reacts to the single tap, sometimes not. Any help to solve this issue is highly appreciated!
To achieve your goal:
Add tap gesture recognizer on your table view, do not forget to set numberOfTapsRequired = 2
Do not implement didSelectRowAtIndexPath method
To prevent table view cells from changing their background color after single tap, set in interface builder, Attributes Inspector tab, table view "selection" attribute to "No selection" or table view cell "selection" attribute to "None".
If you want to get indexpath of cell being doubletapped, in your gesture recognizer handler method get tap location in tap.view and use indexPathForRowAtPoint method of tableView:
let tapLocationPoint = tap.location(in: tap.view)
let tappedCellIndexPath = tableView.indexPathForRow(at: tapLocationPoint)
I use this code to detect a long pressed element:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// some stuff
if let labelCell = model as? TTTLabelCell{
labelCell.delegate = self
labelCell.textLabel.addGestureRecognizer(longPressRec)
}
}
This is the gesture recognizer
longPressRec.addTarget(self, action:#selector(labelLongPressed))
And this is the selector
func labelLongPressed(){
print("Label Long pressed")
// labelCell.backgroundColor = UIColor.blue
}
What I want to achieve, as commented on the code, is to pass the selected object (labelCell) to the selector labelLongPressed() which will allow me to change some attributes. Do you have an idea how to do that?
change func as below :
func labelLongPressed(_ sender: UITapGestureRecognizer){
print("Label Long pressed")
let labelCell: TTTLabelCell = sender.view // track as per your view hierarchy
labelCell.backgroundColor = UIColor.blue
}
Firstly, I'd suggest adding the gesture recognizer to the cell itself rather than to the text label. This gives the user a bigger tap area, and makes it easier to reference the cell when the long press is recognized.
labelCell.addGestureRecognizer(longPressRec)
Add an argument to your gesture action, to pass the gesture recognizer. Then we can use the recogniser's view, to get a reference to the cell — since we are adding the gesture recogniser directly to the cell.
func labelLongPressed(_ recognizer: UIGestureRecognizer) {
guard recognizer.state == .began else { return }
print("Label Long press began!")
if let labelCell = recognizer.view as? TTTLabelCell {
labelCell.backgroundColor = .blue
}
}
Finally, when adding the target to the Gesture Recognizer, update the Selector to match our function signature.
longPressRec.addTarget(self, action:#selector(labelLongPressed(_:)))
In my Swift code, I have a UICollectionViewCell with 3 buttons (all three have IBActions). From my UICollectionViewController I now want to "catch" the individual button taps.
I've followed this StackOverflow question and I can catch the UICollectionViewCell's touch-up inside up in my CollectionViewController with adding this line to the viewDidLoad
gestureRecognizer.cancelsTouchesInView = false
and with this function
func handleTapForCell(recognizer: UITapGestureRecognizer){
//I can break in here
}
But the piece missing now is how can I figure out which of the three buttons have been tapped? I have set different tags on the buttons but I have not found any place on the gestureRecognizer dealing with these tags.
Any ideas?
I think, you don't need to add Gesture on cell to get a button action of a tableviewCell. This code may help you:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//Your tableviewCell code here
//set tag of cell button
cell.button1.tag = 1
cell.button2.tag = 2
cell.button3.tag = 3
//add action of your cell button
cell.button1.addTarget(self, action: Selector("cellButtonTapped:event:"), forControlEvents: .TouchUpInside)
cell.button2.addTarget(self, action: Selector("cellButtonTapped:event:"), forControlEvents: .TouchUpInside)
cell.button3.addTarget(self, action: Selector("cellButtonTapped:event:"), forControlEvents: .TouchUpInside)
// return cell
}
func cellButtonTapped(sender:UIButton, event:AnyObject){
let touches: NSSet = event.allTouches()!
let touch = touches.anyObject()
let currentTouchPosition: CGPoint = (touch?.locationInView(YOUR_TABLEVIEW_INSTANCE))!
if let indexPath: NSIndexPath = self.YOUR_TABLEVIEW_INSTANCE.indexPathForRowAtPoint(currentTouchPosition)!{
if sender.tag == 1{
//cell first button tap
}else sender.tag == 2{
//cell second button tap
}
else sender.tag == 3{
//cell 3rd button tap
}
}
}
You can follow the protocol/delegate paradigm.
What you need to do is define a protocol in Custom cell. Then make the viewcontroller subscribe to the cell delegate.
Implement the IBActions inside the custom cell class. Call the delegate methods in the IBActions of the buttons. viewcontroller who is delegating for the cell will receive the callbacks for button taps inside the cell.
Using iOS 9 and facing a problem with a UITapGestureRecognizer. I have a ViewController-A with a UITableView. I have added a tableViewCell which has a textLabel. I want to implement tap on the textLabel. So if I tap on textLabel -- it should print on Console or do anything else
Issue: TapRecogniser is not working. Getting the below error:
Following is what I have done:
1) Added a `UITapGestureRecognizer' on the textLabel (From StoryBoard). Enabled User Interaction for the textLabel (the error even now)
2) Following is the IBAction:
#IBAction func nameTap(sender: UITapGestureRecognizer) {
print("a")
}
3) CellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell") as! ThirdViewCell!
cell.nameLabel?.text = "XYZ"
let nameTapRecognizer = UITapGestureRecognizer(target: self, action: Selector("nameTap:"))
nameTapRecognizer.cancelsTouchesInView = false
cell.nameLabel?.addGestureRecognizer(nameTapRecognizer)
return cell
}
P.S:
1) This was working in iOS 8. I have checked..There are no duplicates (there is only one tap recognizer in the entire file and its linked to the textLabel)
2) I don't want to use didSelectRowAtIndexPath method as I need to implement TapGestureRecognizer for more textLabels within the tableViewCell.
are you see the error console Label, and the property as UserInteractionEnabled = NO; see the screen shot
try this
let nameTapRecognizer = UITapGestureRecognizer(target: self, action: Selector("nameTap:"))
nameTapRecognizer.cancelsTouchesInView = false
cell.nameLabel?.tag = indexPath.row // add this
nameTapRecognizer.numberOfTapsRequired = 1 // add this
nameTapRecognizer.delegate =self
cell.nameLabel?.userInteractionEnabled = true // add this
cell.nameLabel?.addGestureRecognizer(nameTapRecognizer)
// method
func nameTap(gesture: UITapGestureRecognizer) {
let indexPath = NSIndexPath(forRow: gesture.view!.tag, inSection: 0)
let cell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell
// Do whatever you want.
}