I'm trying to add a swipe gesture (left/right) in order to hide/show my side menu.
I got it working perfectly on a UIView, however, I'm having trouble with an UITableView.
Here's my code to add my swipe gestures to my TableView:
// Add right swipe gesture recognizer
let rightSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "toggleSideMenu")
rightSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Right
self.timelineTableView.addGestureRecognizer(rightSwipeGestureRecognizer)
// Add left swipe gesture recognizer
let leftSwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "toggleSideMenu")
leftSwipeGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Left
//sideMenuContainerView.addGestureRecognizer(rightSwipeGestureRecognizer)
self.timelineTableView.addGestureRecognizer(leftSwipeGestureRecognizer)
Here's my selector method :
func toggleSideMenu() {
println("ENTER SWIPE")
toggleSideMenuView()
}
I've also done this :
func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
return UITableViewCellEditingStyle.None
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return false
}
However, my selector menu "toggleSideMenu()" is never called when I swipe left or right.
P.S: I've also tried to add those swipe gesture on my UITableViewCell directly but it doesn't work as well.
Anyone has an idea? Thanks a lot for your time!
Thanks to Kirit Modi. Here's the solution to my problem:
Add :
leftSwipeGestureRecognizer.delegate = self
rightSwipeGestureRecognizer.delegate = self
Then add the UIGestureRecognizerDelegate delegate method :
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
return true
}
For me helped
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
because i had two gestures. One from slide menu and one from current VC. So that one from slide menu killed VC's gestures.
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
}
This question already has answers here:
UITapGestureRecognizer breaks UITableView didSelectRowAtIndexPath
(21 answers)
Closed 5 years ago.
I have added UITableView on top of UIView. Added tap gesture to UIView using below code:
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapToClose))
tapGesture.cancelsTouchesInView = false
tapGesture.numberOfTapsRequired = 1
vwForTouchClose.addGestureRecognizer(tapGesture)
when I select on cell didSelectRowAt not getting called instead gesture method is called.
Below is ur code at didSelectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
Please help me to solve this issue.
You have to cancel UIGestureRecognizer's touches on the TableView. Use delegate method of Gesture Recognizer:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:yourTableView]) {
return NO;
}
return YES;
}
What can make UITableViewCell detect only multitouch? If I tap with one finger it doesn't call didSelectRowAtIndex.
Here is my Code:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "bookingSettingsCell", for: indexPath) as! SettingsTableViewCell
if indexPath.row < 3 {
cell.settingSwitch.removeFromSuperview()
}
cell.settingTitle.text = dataForSetting[indexPath.row].first
if dataForSetting[indexPath.row].last != "Pencil" {
cell.settingValue.isHidden = true
cell.settingChangable.isHidden = true
cell.settingSwitch.isHidden = false
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
DispatchQueue.main.async(execute: {
if indexPath.row < 3 {
let destinationVC = self.storyboard?.instantiateViewController(withIdentifier: "DatePicker") as! DatePickerViewController
destinationVC.modalPresentationStyle = .overCurrentContext
destinationVC.delegate = self
self.present(destinationVC, animated: true, completion: nil)
}
})
}
UITableViewCell class:
class SettingsTableViewCell: UITableViewCell {
#IBOutlet var settingTitle: UILabel!
#IBOutlet var settingChangable: UIImageView!
#IBOutlet var settingValue: UILabel!
#IBOutlet var settingSwitch: UISwitch!
override func awakeFromNib() {
super.awakeFromNib()
settingSwitch.transform = CGAffineTransform(scaleX: 0.65, y: 0.60)
}
}
You can handle the behavior of uitableviews's didSelectRowAt method after implementing the delegate methods of gesture recognizer. This prevents the undefined behavior of taps between uiview and tableViewCell and keeps the record of touches.
UIGestureRecognizerDelegate method:
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
println("in shouldReceiveTouch")
gestureRecognizer.delegate = self
if (touch.view == tableView){
println("touching tableView list")
return false
}
else{
println("touching elsewhere")
return true
}
}
I figured out that this happened because I added UITapGestureRecognizerto my superview so I can hide keyboard on touch. But actually still don't understand why in this case it worked with multitouch? I would suggest that my mistake should block all tap events.
I think that the problem isn't in didSelectRowAt but in a UITableViewCell...
are you using the constraint logic when you design the xib?
Is possible that some object (label or imageView) create problem with touch...
review your constraint or design your tableViewCell direct in uitableView from storyboard.
You can solve this problem by adding the UIGesture recogniser delegate in your class. Add the UIGestureRecognizerDelegate in your class. Follow these steps:-
/*
class SignupInstructorViewController: UIViewController, UIGestureRecognizerDelegate
Note:- Now for identify whether you are tapping on tableView or some where else you have to implement this gesture delegate like this.
//MARK:- Gesture delegates
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
// if user touch the tableview then below condition will be true
if touch.view != nil && (touch.view!.isDescendantOfView(tableViewName)) {
return false
}
return true
}
HopeFully, it will works for you.
Thanks in Advance.
*/
You can check if this happens due to any gesture by removing all the gestures of the view as below and try.
view.gestureRecognizers?.removeAll()
Better to find the exact gesture which cause the issue and handle it properly.
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.
I have a ViewController which has textSearchTableView: UITableView and searchBar: UISearchBar
I added UITapGestureRecognizer to dissmis the keyboard
override func viewDidLoad() {
// ...
self.tap = UITapGestureRecognizer(target: self, action: "DissmissKeyboard")
self.tap.delegate = self
self.view.addGestureRecognizer(self.tap)
// ...
}
func DissmissKeyboard()
{
view.endEditing(true)
}
I have added this function to prevent breaking (didSelectRowAtIndexPath) function after selecting the cell
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if touch.view.isDescendantOfView(self.textSearchTableView) {
return false
}
return true
}
But the problem is: when the keyboard is enabled and i want to dissmiss it,
if i click on the textSearchTableView, (didSelectRowAtIndexPath) will run
How can i dissmiss the keyboard if i click on the tableView without calling (didSelectRowAtIndexPath) ? and I don't want to break this function as well
I hope that I describe the problem well
Thanks a lot
Re-write your didSelectRowAtIndexPath like this:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if (self.searchBar.isFirstResponder())
{
self.searchBar.resignFirstResponder()
}
else
{
//Do something here
}
}
Alternatively: We usually use this approach in tableviews.
self.tableView.keyboardDismissMode = .OnDrag
This will dismiss keyboard when a drag begins in the tableview.
How about you have your tableview's delegate return nil for
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath
As willSelectRowAtIndexPath is probably what you want but not what you asked for: dismissing the keyboard is done by sending the first responder resignFirstResponder, for sake of answering the actual question.