How to call didSelectRowAtIndexPath method with UITapGestureRecognizer? - ios

I've searched for hours on Google and Stackoverflow, tried them but no luck.
I have a UITableView tblDepartment and a UISearchBar studentSearch above it.
I add a UITapGestureRecognizer to dismiss the keyboard from studentSearch textbox when users tap outside the search box:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.tblDepartment addGestureRecognizer:gestureRecognizer];
- (void)hideKeyboard
{
[studentSearch resignFirstResponder];
}
After that, the method didSelectRowAtIndexPath:(NSIndexPath *)indexPath isn't called anymore when I select row in tblDepartment. I know gestureRecognizer is the reason.
So, how can I hide the keyboard and still allow user to select row?
I tried this code but it didn't work:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isDescendantOfView:tblDepartment]) {
return NO;
}
return YES;
}

Set the gesture recognizer cancelsTouchesInView property to NO, it's YES by default, it prevents touches from reaching the underlying views if the GR recognizes its gesture.

Related

iOS Disable Double Tap gesture recognizer in Swift

I am working on a app using TableView now i am facing an issue listed below.
Inside my TableView there is UITextView on it, that MUST be selectable, but not editable (because I need to use and proceed links).
My issue is:
when I tap on a link as everybody does, it doesn't work. I need to hold it a bit longer to make it work. I thought that it is because of "Selectable" property brings in a Double Tap Gesture recognizer, so my textView checks if there is a second tap, but I don't know how to find and remove only double tap recognizer.
What should I do?
Thank you.
Have you considered replacing the TextView with a UIWebView, and just do a loadHTMLString function?
This way when you tap on a link, it will open instantly? You can even have a UIWebView delegate and do what you want when the link is pressed(Custom UIWebView instead of auto opening in safari etc)
You've to handle tap event.. Through this code
tapGesture.numberOfTapsRequired = 1
OR
To do this, you will need to embed one in your UITableViewCell. But there's no need to create a custom cell. Here is the basic idea of what you will want to do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UITextView *comment = [[UITextView alloc] initWithFrame:CGRectMake(cell.frame.origin.x, cell.frame.origin.y, cell.frame.size.width, tableView.rowHeight)];
comment.editable = NO;
comment.delegate = self;
[cell.contentView addSubview:comment];
[comment release];
}
return cell;
}
You will, of course, need to set your rowHeight if you don't want the standard 44pt height that comes with the cell. And if you want actual cells, you'll need to add your own logic so that only the cell you want is a textView, but this is the basic idea. The rest is yours to customize to your fitting. Hope this helps
EDIT: to bypass the textView to get to your cell, there are two ways to go about this.
1) you can make a custom textView class and overwrite touchesBegan to send the message to super:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
}
this will send the touch events to its superview, which would be your tableView. Considering you didn't want to make custom UITableViewCells, I imagine you probably don't want to make a custom textView class either. Which leads me to option two.
2) when creating the textView, remove comment.editable = NO;. We need to keep it editable, but will fix that in a delegate method.
In your code, you will want to insert a textView delegate method and we'll do all our work from there:
EDIT: changing this code to use with a UITableViewController
- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
// this method is called every time you touch in the textView, provided it's editable;
NSIndexPath *indexPath = [self.tableView indexPathForCell:textView.superview.superview];
// i know that looks a bit obscure, but calling superview the first time finds the contentView of your cell;
// calling it the second time returns the cell it's held in, which we can retrieve an index path from;
// this is the edited part;
[self.tableView selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
// this programmatically selects the cell you've called behind the textView;
[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];
// this selects the cell under the textView;
return NO; // specifies you don't want to edit the textView;
}
If that's not what you wanted, just let me know and we'll get you sorted out
Finding and Removing Double Tap Gesture recognizer
Objective C
- (void)addGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]])
{
[(UITapGestureRecognizer *)gestureRecognizer setNumberOfTapsRequired:1];
gestureRecognizer.enabled = NO;
}
}
Swift
func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer)
{
if gestureRecognizer.isKindOfClass(UITapGestureRecognizer)
{
(gestureRecognizer as! UITapGestureRecognizer).numberOfTapsRequired = 1
gestureRecognizer.enabled = false
}
}

Detecting touch inside UITableViewCell subview

I am unclear where I should add the UIGestureRecognizer code to corresponding subviews of a UITableViewCell. I have read all the related questions I could find. Right now my cells and cell's subviewsare generated inside of cellForRowAtIndexPath. I have tried to add the Gesture inside of cellForRowAtIndexPath with this:
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[mySubview addGestureRecognizer:tapGesture];
tapGesture.cancelsTouchesInView = YES;
tapGesture.delegate = self;
However, this detects nothing. To verify my UIGesture recognizer is working I have used the above code on the tableView itself, and it does register touches as expected. Furthermore, when the tableView has the above gesture attached the below code is also being called as expected:
-(BOOL) gestureRecognizer:(UITapGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
NSLog(#"shouldRevceiveTouch");
return YES;
}
- (BOOL)gestureRecognizer:(UITapGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UITapGestureRecognizer *)otherGestureRecognizer
{
NSLog(#"simultaneously");
return YES;
}
I have tried to remove the GestureRecognizer from the tableView and inside of cellForRowAtIndexPath I have tried to attach the GestureRecognizer to the cell itself, any of its subviews, nothing else gets a touch detected. (None of the above code is triggered)
Clearly I am adding the GestureRecognizer incorrectly. Where/When would be an appropriate location/time to add the GestureRecognizer?
Thank you.
I've done similar thing, but it was UILongPressGestureRecognizer. I think there is no big difference (because all touches are received by UITableView). I've added gesture recognizer in controllers viewDidLoad method (NOT IN cell).
- (void) tableViewLongPress:(UILongPressGestureRecognizer *)gestureRecognizer {
CGPoint p = [gestureRecognizer locationInView:self.messageTableView];
NSIndexPath *indexPath = [self.messageTableView indexPathForRowAtPoint:p];
if (indexPath == nil)
NSLog(#"long press on table view but not on a row");
else {
UITableViewCell *cell = [self.messageTableView cellForRowAtIndexPath:indexPath];
CGPoint pointInCell = [cell convertPoint:p fromView:self.messageTableView];
}
}
You can change Long press to regular one and try it yourself
I needed to detect touches on different subviews inside my cell. also handling iOS 9's UITableViewCellContentView.
First I overrided touchesBegan inside the my custom UITableViewCell
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:touch.view];
// Imagine I have 2 labels inside my cell
CGPoint convertedPoint = [self.firstLabel convertPoint:point fromView:touch.view];
if ([self.firstLabel pointInside:convertedPoint withEvent:nil]) {
// Touched first label
return;
}
convertedPoint = [self.secondLabel convertPoint:point fromView:touch.view];
if ([self.secondLabel pointInside:convertedPoint withEvent:nil]) {
// Touched second label
return;
}
// no labels touched, call super which will call didSelectRowAtIndexPath
[super touchesBegan:touches withEvent:event];
}
And to fix support in iOS 9 we should override awakeFromNib or just disable the cell user intercations somehwere else if cell is not in Storyboard / xib:
- (void)awakeFromNib {
// Initialization code
self.contentView.userInteractionEnabled = NO;
}
of course we shouldn't forget to set our label user interactions enabled.
Not sure exactly what you are trying to do. If you just want to detect if the user taps on a cell within the table then you don't need to implement a gesture recognizer. Just implement the delegate method below to detect when a row from the table has been selected then process the elements of the row such as getting the subview, etc.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Do all my cool tap related stuff here for example, get the row that was tapped:
UITableViewCell *cell= [tableView cellForRowAtIndexPath:indexPath];
// get your subview (assume its a UIImageView) from cell - one way to do it below
UIImageView photo = (UIImageView *)[cell.contentView viewWithTag:PHOTO_TAG];
}
If you describe your problem a little further then perhaps I can offer additional suggestions.

UIView "stealing" touch from UITableView

I have an autocomplete table that I create the frame for when the user types anything in a search bar button item.
The problem is, I want to be able to dismiss the tableview when the user touches outside of it or the table, so naturally I added a tap touch recogniser to the main view.
Problem is, the view "hijacks" the touches from the table, so when you try to touch the table it dismisses it (which makes perfect sense as the table is a subview of that UIView)
Anyone have any smart solutions?
(My initial hunch is to put the UITableView in a new window on top of the view's window, but I would prefer if there was something more elegant)
Maybe you can try
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view.superview.superview isKindOfClass:[UITableView class]]) return NO;
else return YES;
}
//Init recognizer
UIGestureRecognizer *gestureRecognizer;
gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[gestureRecognizer setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:gestureRecognizer];
self.tapRecognizer = (UITapGestureRecognizer *)gestureRecognizer;
gestureRecognizer.delegate = self;
[gestureRecognizer release];
and put some stuff for your gesture in
- (void)handleTap:(UITapGestureRecognizer *)recognizer {
}
Hope it helps :)
may be you can try
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
methods for table view selection of row user will feel that user selected the value
and for
and for outside the table use uiviews touch begin methods and check for rect
CGRectContainsPoint(<#CGRect rect#>, <#CGPoint point#>)

Add a TapGestureRecognizer to whole view except UICollectionView cells

I'd like to add a TapGestureRecognizer to cover the whole screen of a UICollectionViewController except the UICollectionViewCell cells.
The closest I got was
-(void) viewDidLoad {
...
UITapGestureRecognizer *tapAnywhere = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(addBoard:)];
[self.collectionView addGestureRecognizer:tapAnywhere];
}
Problem: When I tap a cell the prepareForSegue method is not called. The UITapGestureRecognizer seems to cover the cell.
Which View in a UICollectionViewController is the right one to attach the GestureRecognizer to retain its default cell "tap to segue" functionatlity?
Implement Gesture Recognizer delegate method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UICollectionViewCell class]]) //It can work for any class you do not want to receive touch
{
return NO;
}
else
{
return YES;
}
}

didSelectRowAtIndexPath does not trigger in ViewController

So, I've added a UITableViewController and UITableViewCell into a UIViewController and while the cellForRowAtIndexPath delegate method works, didSelectRowAtIndexPath does not. Does anyone have any ideas?
EDIT 2: The delegate for the UITableView is set to the UIViewController.
EDIT 3: I found the answer to my issue on another Stack question here. Basically I had a UITap... on my [self view] that was blocking the didSelectRow.... I have no idea why the tap blocks the delegate method and I also have no idea how to get both the tap and the table working together simultaneously.
EDIT: The part that bugs me is that I've gotten this exact setup working on an earlier app. So that means I've missed a step somewhere along the way. The thing is, I've combed over all the steps and have compared previous app vs current app and I really have no idea what I missed.
I've added logging to both delegate methods and while one outputs, the other does not.
ViewController.h
#import "...TableViewCell.h"
...
UITableViewDataSource,
UITableViewDelegate
...
ViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"cellForRowAtIndexPath");
...
return Cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"didSelectRowAtIndexPath");
}
...TableViewCell.h (contents not important)
...TableViewCell.m (contents not important)
I found the answer on another StackOverflow question.
I had a UITapGestureRecognizer added to [self view] which I commented out, and then the delegate method worked.
Can anyone please tell me why this worked and also how I can get the UITapGestureRecognizer working on the same screen as the UITableView?
// Hide keyboard when user taps outside of it
UITapGestureRecognizer *tapGestureRecognizer =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(hideKeyboardOnTap)];
//[[self view] addGestureRecognizer:tapGestureRecognizer];
EDIT: Corrected typo of UITapeGestureRecognizer to UITapGestureRecognizer
have you set the delegate of the tableView?
myTableView.delegate = self;
EDIT: My bad, did not read that cell for row is being called.
You say that you have used a custom tableViewController. If you have overridden the didSelectRowAtIndexPath method, it might be important to call [super didSelectRowAtIndexPath:] in the tableViewController
EDIT 2: One more thing. I do not know the reason for this, but I faced the same issue some time back in a viewController. I resolved it by adding an empty implementation of didDeselectRowAtIndexPathin the same viewController. Try adding it to your table's delegate controller.
To answer to the question "how I can get the UITapGestureRecognizer working on the same screen as the UITableView";
You should "inform" your GestureRecognizer that other Recognizer can handle the same gesture:
You do that by implementing the method of UIGestureRecognizerDelegate
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
This is a small exemple...
#interface MyController : UIViewController<UIGestureRecognizerDelegate>
{
}
#end
-(void)viewDidLoad
{
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionOnTapGesture:)];
[gr setNumberOfTapsRequired:1];
[gr setDelegate:self];
[self.view addGestureRecognizer:gr];
}
-(BOOL) gestureRecognizer:(UIGestureRecognizer *) gestureRecognizer shouldRecognizeSimultaneouslyGestureRecognizer:(UIGestureRecognizer *) otherGestureRecognizer
{
return YES;
}
Check in the interface builder if the property selection is set to 'No selection'.
Change it to 'Single selection' or other option according to your needs.
This might be the reason why didSelect is not getting triggered.

Resources