iOS Disable Double Tap gesture recognizer in Swift - ios

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
}
}

Related

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.

Dismiss keyboard for UITextfield in UITableView cell

I have a UITableView to which i've assigned a UITextField to each cell. I want to be able to accept input from each text field and dismiss the keyboard when the user taps anywhere on the screen other than the keyboard. This is the code I have so far, but I find the keyboard only gets dismissed when im on the last cell in the table.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [self.gradesTableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
self.tf = [[UITextField alloc] initWithFrame:CGRectMake(225, (cell.contentView.bounds.size.height-30)/2, 50, 30)];
[self.tf setDelegate: self];
self.tf.tag = indexPath.row;
self.tf.textAlignment = NSTextAlignmentCenter;
self.tf.placeholder = #"0";
self.tf.backgroundColor = [UIColor grayColor];
self.tf.borderStyle = UITextBorderStyleRoundedRect;
self.tf.keyboardType = UIKeyboardTypeDecimalPad;
[cell addSubview:self.tf];
cell.textLabel.text = [self.adderArrayLabels objectAtIndex:indexPath.section];
return cell;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
self.tapGR = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap)];
[self.view addGestureRecognizer:self.tapGR];
NSLog(#"Started editing");
}
Ive tried both endEditing: and resignFirstResponder but both only dismiss the keyboard when im on the textfield in the last cell.
- (void)tap {
[self.tf endEditing:YES];
//[self.tf resignFirstResponder];
NSLog(#"tap called");
self.tapGR.enabled = NO;
}
With the NSLog statements in the code I can confirm the method tap is called every time the appropriate tap gesture is recognized but still the keyboard stays. How do I fix this?
The problem is here:
self.tf
Your class has a text field property, and every time you create a new text field, you assign it to this property. Then, you only try to endEditing: or resignFirstResponder on this property, which will always be the text field on the cell most recently created.
You don't need this property at all and can just use a local text field variable when creating the cells.
Then change your tap method to this:
- (void)tap {
[self.view endEditing:YES];
NSLog(#"tap called");
self.tapGR.enabled = NO;
}
And truly, the method should probably be: - (void)tap:(id)sender;
Also, as I commented, the gesture recognizer should be added in viewDidLoad. We only need to add it once, not each and every time a text field begins editing. The only reason to add it every time a text field begins editing is if you're also removing it every time the text field ends editing... but as the method that the gesture calls simply gets rid of the keyboard, I see no reason to do that.

iphone - perform segue from custom TableCellView

I have a UITableView in which I am populating custom built UITableViewCells. These have a picture and a few labels.
Is there any way that when click on the picture that it performs a certain segue but when I click on each of the labels it performs different segues. I only want these segues performed when I click on the UIImageView or the UILabels.
I am currently playing with the following idea.
Add gesture recogniser to UIImageView and UILables when creating them in cellForRowAtIndexPath
The above touch gesture will trigger the segue
My code looks like this in the UITableView cellForRowAtIndexPath delegate where I create my UITableViewCells
cell.myImage.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(doSomething:)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[cell.myImage addGestureRecognizer:singleTap];
This overrides the didSelectRowAtIndexPath delegate for the table view when I click on the UIImageView so I've tried triggering the segue from the doSomething: function but this function doesn't know the UITableView indexPath so cannot send the right information to the destination viewcontroller (it always sends 0).
I'm sure there must be an easy away to do this
Any ideas welcome. Thanks in advance.
You can get NSIndexPath of cell myImage belongs to by adding following to tap handler doSomething:
- (void)doSomething:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
CGPoint touch = [sender locationInView:self.tableView];
NSIndexPath *indexPath = [self.tableView indexPathForRowAtPoint:touchPoint];
NSLog(#"indexPath: %#", indexPath);
//Select cell and trigger didSelectRowAtIndexPath:
[self.myTableView selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
[self tableView:self.myTableView didSelectRowAtIndexPath:indexPath];
}
}
UIGestureRecognizers have a view property you can access. Iterate over that view's superviews until you have the UITableViewCell and call:
[tableView indexPathForCell:cell];
that should give you the IndexPath.

iphone - didSelectRowAtIndexPath: only being called after long press on custom cell

I am creating one table view based application. I have created a custom table cell for table, that contains 2 labels, 1 image and 1 button. The table view Data source method is working properly. I am using xib for both custom cell and view controller class and i connect delegate and data source to the file's owner. But the problem is when i select the table row, didSelectRowAtIndexPath is not getting fire. As mentioned the only way to fire it is to hold down on the cell for about 3-4 seconds. Does anyone have any idea why this is happening?
Thanks for any pointers...
Here is my table view methods..
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [finalAddonsArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NewCustomCell *cell = (NewCustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *nib=[[NSBundle mainBundle]loadNibNamed:#"NewCustomCell" owner:self options:nil];
cell=[nib objectAtIndex:0];
}
Addons *addons1=[[Addons alloc]init];
addons1= [finalAddonsArray objectAtIndex:indexPath.row];
if (addons1.data == nil) {
cell.ivCategory.image = [UIImage imageNamed:#"blogo.jpg"];
}
else
{
cell.ivCategory.image=[UIImage imageWithData:addons1.data];
}
cell.lblTitle.text = addons1.name;
if (addons1.price == nil) {
cell.lblPrice.text = nil;
}
else{
cell.lblPrice.text = [NSString stringWithFormat:#"%# rs",addons1.price];
}
[cell.button addTarget:self
action:#selector(editButtonPressed:)
forControlEvents:UIControlEventTouchUpInside];
cell.button.tag=indexPath.row;
index = indexPath;
cell.selectionStyle = UITableViewCellSelectionStyleGray;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"sjcjksbcjksbcfkebscf1234567890");
}
One more thing i am getting that if i am using default UITableViewCell instead of custom cell then also my problem is same, delegate method is not getting fire.
Custom cell properties:
same problem happened with me because I have added a tap gesture recogniser over it.
If you have used any gesture recognizer try removing it and check if it causing the problem.
EDIT: Solution as commented by the Ali:
If you have used tap gesture you can use [tap setCancelsTouchesInView:NO];
I was faced with a similar issue:
For me, the problem was because my UITableView was added to an UIScrollView and more specifically to its contentView.
It appears that inside the contentView, I had to stay press 2-3 sec to fire the didSelectRowAtIndexPath method.
I moved my TableView to self.view instead of contentView and it solved the problem!
Maybe you will call the method
[tableView deselectRowAtIndexPath:indexPath animated:NO];
before Push ViewController or Other Operation. Like
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// 1. manual call this method to deSelect Other Cell
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// 2. than do other operation
PushViewController Or Some Animation ....
}
that`s solve my problem .
As others suggested, [tap setCancelsTouchesInView:NO]; does the trick.
However, I want to make one thing clear:
If you think that you did not implement tapgesture and are curious about why you had to add your view into the protected views, check out your class because most probably you have inherited some class and that class includes tap gesture recognizer in it.
In my case, I did the following:
- (NSMutableArray *)tapProtectedViews
{
NSMutableArray *views = [super tapProtectedViews];
[views addObject:self.mTableView];
return views;
}
Edit for Swift 4+
Assuming you have a UITapGestureRecognizer instance named tapGesture:
func disableTapGesture(){
tapGesture.cancelsTouchesInView = false
}
Or you can:
if self.view.gestureRecognizers?.isEmpty == false{
for recognizer in self.view.gestureRecognizers!{
self.view.removeGestureRecognizer(recognizer)
}
}
Dear i faced the same problem. When i tapped the cell but didselectrowatindexpath was not called than it was suddenly called when i released the button after pressing it for few seconds.
If you are facing the same issue there must be a
1. UITapGestureRecognizer that is creating problem for you
or
2. a scroll view in which you placed you table view.
Thus you should remove the gesture or the super scroll view in which your table view is placed
If you have custom gesture object on your view, check override func gestureRecognizerShouldBegin(_ gesture: UIGestureRecognizer) -> Bool delegate. Compare custom gesture with sender gesture, If its not custom gesture object, pass it to the the super. So system gestures/taps won't get blocked.
I'm not sure about this, but Delays Content Touches might have something to do with it.

Hiding a Button in a UITableViewCell

I currently have a table with 8 rows that each have a label on the right side and a button on the left. I was hoping that I could have all the buttons hidden until the user presses an "edit" button in the top right corner and then they would appear allowing the user to interact with each table cell. I don't know if this is possible, because they are in UITableViewCells or if there is an easier method to summoning a button for each cell
UPDATE
okay so I have placed in all the hidden properties and there seem to be no errors, but the app doesn't recognize any of it. The buttons remains unhidden despite the fact that they are set to be initially hidden. Here is my code
Here is my Table Cell code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"BlockCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = #"Free Block";
UIButton*BlockButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
BlockButton.frame = CGRectMake(225.0f, 5.0f, 75.0f, 35.0f);
[BlockButton setTitle:#"Change" forState:UIControlStateNormal];
[BlockButton addTarget:self action:#selector(Switch:) forControlEvents:UIControlEventTouchUpInside];
Blockbutton.backgroundColor = [UIColor colorWithRed:102/255.f
green:0/255.f
blue:51/255.f
alpha:255/255.f];
Blockbutton.hidden = YES;
[cell addSubview:BlockButton];
return cell;
}
and here is my method code:
- (IBAction)Editmode:(UIButton *)sender
{
Blockbutton.hidden = !Blockbutton.hidden;
[self.tableView reloadData];
}
any thoughts or ideas as to what might be the issue?
You'll need to create a UITableViewCell subclass if you don't already have one. In that class, override setEditing:animated: and if the new value is YES, then enable/add/unhide the button.
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (editing) {
// add your button
someButton.hidden = NO;
} else {
// remove your button
someButton.hidden = YES;
}
}
It would be optional, but you are encouraged to animate the change if animated is YES.
Note: this assumes you have the edit button already hooked up the change the editing mode of the UITableView. If you don't, call setEditing:animated: on the UITableView in the button action. This will automatically call setEditing:animated: on each visible table cell.
The trick here is to keep in mind that a table's cells are determined by cellForRowAtIndexPath:. You can cause that method to be called all over again by sending the table reloadData:.
So, just keep a BOOL instance variable / property. Use the button to toggle that instance variable and to call reloadData:. If, at the time cellForRowAtIndexPath: is called, the instance variable is YES, set the button's hidden to YES; if NO, to NO.
take a BOOL variable which defines the whether to show delete button or not, use this BOOL var to for btnName.hidden = boolVar, initially make boolVar = NO, when user taps on edit toggle bool var and reload the tableview.
Another option is to test if you are in edit mode in the cellForRowAtIndexPath method.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = //(obtain your cell however you like)
UIButton *button = cell.button; //(get button from cell using a property, a tag, etc.)
BOOL isEditing = self.editing //(obtain the state however you like)
button.hidden = !isEditing;
return cell;
}
And whenever you enter editing mode, reload tableView data. This will make the table view ask for the cells again, but in this case the buttons will be set not to hide.
- (void)enterEditingMode {
self.editing = YES;
[self.tableView reloadData];
}

Resources