There is a UILable above the UITableVIew, the UILable and the UITableVIew are brothers, and I added GestureRecognizer to the UILable, but this gesture cannot be triggered, why?
Make sure you are set userInteractionEnabled is true
In your viewDidLoad
YOUR_Label.isUserInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: #selector(self.uilabelTapped(_:)))
YOUR_Label.addGestureRecognizer(tap)
In your ViewController
#objc func uilabelTapped(_ sender: UITapGestureRecognizer) {
print("UILabel Tapped")
}
Make sure your tableView and uilabel are child of same view
Hope this will help you
Related
I've set up TapGuestureRecognizer within my ViewDidLoad() to dismiss keyboard. My implementation as follows
class AddRegistrationTableViewController: UITableViewController, UITextFieldDelegate, SelectRoomTableViewControllerDelegate {
...
override func viewDidLoad() {
super.viewDidLoad()
emailAddressTextField.delegate = self
...
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
tableView.addGestureRecognizer(tapGestureRecognizer)
}
...
#objc func dismissKeyboard() {
emailAddressTextField.endEditing(true)
}
So far so good, this works in dismissing the text field.
But within the Table View Controller, I also have a segue linked up to a cell - which isn't registering the tap (because of the gesture recognizer) to follow through with the segue. I'll need to use 2 fingers to tap on the cell for the segue to be performed. And I've tried removing my above implementation of addGestureRecognizer in the code, and the segue performed as per expectation.
So this led me to believe that the gesture recogniser is inhibiting touch events from registering. Any workarounds or solution that I can implement?
Instead of tap to dismiss, implement scroll to dismiss by setting the table view's keyboardDismissMode to .onDrag. Have your interface work with the framework, not against it.
If you want to dismiss the keyboard why aren't you using the UITableViewDelegatemethod instead of UITapGestureRecognizer.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
emailAddressTextField.endEditing(true)
}
one more thing, the table view is getting the tap gesture and not cell, thats why the segues are not called.
A good solution for this would be implementing the UIGestureRecognizerDelegate:
class AddRegistrationTableViewController: UITableViewController, UIGestureRecognizerDelegate, UITextFieldDelegate, SelectRoomTableViewControllerDelegate {
...
override func viewDidLoad() {
super.viewDidLoad()
emailAddressTextField.delegate = self
...
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
tapGestureRecognizer.delegate = self // You set the UIGestureRecognizerDelegate here
tableView.addGestureRecognizer(tapGestureRecognizer)
}
...
#objc func dismissKeyboard() {
emailAddressTextField.endEditing(true)
}
// In this UIGestureRecognizerDelegate's method we will check if the text field is actually being edited
// and if it's not the case, we will cancel this touch for the gesture
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return emailAddressTextField.isEditing
}
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 have a UITableViewDataSource with the following
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: OutletDetails.cellIdentifier) as! OutletDetails
cell.selectionStyle = .none
cell.isUserInteractionEnabled = true
cell.location = "Some location will be here"
let tap = UITapGestureRecognizer(target: self, action: #selector(locationClicked))
tap.cancelsTouchesInView = false
tap.numberOfTapsRequired = 1
cell.location.addGestureRecognizer(tap)
}
where cell.location is a UILabel object. What I'm trying to do here is to detect tap events on the UILabel. I looked all over the Internet and everyone is suggesting this method, however, this code is not working in my case. The method locationClicked is not being called at all. Can anyone tell me what's wrong with my code?
Edit
One more thing, is it a good idea to do it this way memory-wise? I mean if we have a long list, then many UIGestureRecognizer objects will be generated for each cell. This is because the method will be called a lot while scrolling the items.
Add tap gesture to the object and enable its user interaction. Yes you can take button as well.
//Adding tap gesture
let cellNameTapped = UITapGestureRecognizer(target: self, action: #selector(nameTapped))
nameLabel.isUserInteractionEnabled = true// UILabel made available for touch interaction
nameLabel.addGestureRecognizer(cellNameTapped) //gesture added
//Method called on touch of nameLabel
#objc func nameTapped(tapGestureRecognizer: UITapGestureRecognizer){
//print(tapGestureRecognizer.view)
}
Since you're dequeuing a cell, you will need to somehow get a reference to the UITapGestureRecognizer and either remove it or reuse it. Otherwise every time you reuse a cell, you will be laying another recognizer onto the one that is already on the cell. If you're subclassing the UITableViewCell you can just add the recognizer as a property.
However, using the code you posted I'm suggesting you use a UIButton and add a tag so you can get a reference to it later. You can set the bounds of the button equal to the bounds of the label. Try something like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: OutletDetails.cellIdentifier) as! OutletDetails
cell.selectionStyle = .none
cell.isUserInteractionEnabled = true
cell.location = "Some location will be here"
// If we don't already have a button on our cell, create one and set the tag
if cell.viewWithTag(103) as? UIButton == nil {
let newButton = UIButton(frame: cell.location.bounds)
newButton.tag = 103
newButton.addTarget(target: self, action: #selector(locationClicked), for: .touchUpInside)
}
}
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.
I have several tap gestures being created and recognized on different UIViews from in my TableViewController and the different gestures are being recognized correctly. As seen in this code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("CustomCell", forIndexPath: indexPath) as! CustomCell
let tapOnView1 = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
let tapOnView2 = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
cell.View1.addGestureRecognizer(tapOnView1)
cell.View1.userInteractionEnabled = true
cell.View2.addGestureRecognizer(tapOnView1)
cell.View2.userInteractionEnabled = true
return cell
}
My Handle tap looks like this:
func handleTap(sender:UITapGestureRecognizer) {
let tappedView = sender.view
self.tableView.beginUpdates()
if tappedView == cell.View1 {
print("View 1 Tapped")
} else if tappedView == cell.View2 {
print("View 2 Tapped")
}
}
I wanted to move all this code to my CustomCell UITableViewCell class as there are actually several more UIViews that have different actions that need to be taken on a tap. Additionally moving them all to the Cell itself seems to me to be the right thing to do. I searched for answers but the only true answer I have seen is to use buttons and there are several reasons that this is really not an option for me without some serious refactoring and rewriting. I have tried several iterations to the following code in my CustomCell class:
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tapOnView1 = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
addGestureRecognizer(tapOnView1)
let tapOnView2 = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
addGestureRecognizer(tapOnView2)
}
and this handleTap function:
func handleTap(sender: UITapGestureRecognizer) {
if delegate != nil && item != nil {
if sender.view == view1 {
print("view1 tapped")
} else {
print("view2 tapped")
}
}
}
The tap for view1 is never called. It only ever calls the view2 tap no matter where in the cell I tap. I have tried using different Selector functions (i.e. handleTapOne: for View1, and handleTapTwo: for View2) but I can't seem to figure out how to do this.
Again it works in my UITableViewController but it does not work when I try to move all of the tap recognizers to the UITableViewCell.
Thanks for the help.
iphonic answered my question above. I was an idiot I guess. staring at a problem for two long and missing the most simplest of things.