How to handle a tapping on non-cell area of UITableView - ios

I have a UITableView with a couple of UITableViewCells in it. Because I only have a couple of cells, there is an area of the table view that's not covered by the cells. And I want to do something when the empty area is tapped.
I tried adding a UITapGestureRecognizer on the table view. It detects the tapping on the empty area, but then the cells fail to respond to tapping. I tried adding the tap gesture recognizer on the super view of the table view, but the result is the same.
There must be a way to do this, but I can't quite figure it out yet. Is there any way to achieve what I want to do?

Try this:
initialize and add the UITapGestureRecognizer to your tableView:
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
gr.delaysTouchesBegan = YES;
gr.delegate = self;
[_tableView addGestureRecognizer:gr];
implement the gesture recognizer delegate method:
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
CGPoint tapPoint = [gestureRecognizer locationInView:_tableView];
UIView * clickedView = [_tableView hitTest:tapPoint withEvent:nil];
NSString *viewClassName = NSStringFromClass(clickedView.class);
return ![viewClassName hasPrefix:#"UITableViewCell"];
}
this way every tap you do outsude cells (but inside the tableview) will be recognized with your UITapGestureRecognizer

The last line: return ![viewClassName hasPrefix:#"UITableViewCell"];
should be changed to return [viewClassName hasPrefix:#"UITableView"]; since the cell you are clicking doesn't have to be a UITableViewCell, but a UIView or some other custom view

Related

UICollectionView within UIScrollView: Long Press

I have added a UILongPressGestureRecognizer to my UICollectionView that is within a subclass of UIScrollView. (The UIScrollView is paged so there are 3 horizontally stacked UIViewControllers).
My code to add the UILongPressGestureRecognizer:
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
longPress.delegate = self;
longPress.minimumPressDuration = 0.5;
longPress.delaysTouchesBegan = YES;
[self.collectionView addGestureRecognizer:longPress];
And an NSLog in my handleLongPress: method. Currently I hold down on a UICollectionViewCell, it highlights, but the long press is not activated. I believe my UIScrollView subclass is consuming the long press and not passing along to the UICollectionView. When I lift my finger, the didSelectItemAtIndexPath: method is called.
In my UIScrollView subclass, the only customization I have is the following:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(nonnull UIGestureRecognizer *)otherGestureRecognizer {
// This line enables the swipe to delete in the Messaging VC.
return ([otherGestureRecognizer.view.superview isKindOfClass:[UITableView class]]);
}
This was done to enable cell swiping in my UITableView, which is one of the pages of my UIScrollView. The swiping works no problem, and I have tried a number of similar checks for UICollectionView and UICollectionViewCell here but have not gotten the long press to register yet. Any advice appreciated.
Edit: I have added the long press on another UICollectionView and it is functional, but the cell never shows highlighted/selected status. I guess that is a clue as to why I can't get this long press gesture to fire.
My issue was that I was adding the gesture recognizer in the -init method. That did not work. Simply moving the code to -viewDidLoad fixed the problem.

Hide UITableView on touches outside the tableview

I have a small UITableView that is hidden when the view is loaded. When i click on "SHOW" UIButton, the UITableView is made visible by myTableView.hidden=NO;
I want to hide UITableView when a user touches outside its frame. Thanks for any help!
Best Approach
Simple.Before show up the UITable View add one more grayed out/Transparent view then add tap gesture recogniser on it to hide it . That's it.
Show Overlay View first - alpha will be 0.5f and background color should be clear color.
show the table view.
NOTE: over lay view should have tap recogniser which will hide the overlay and table view
in View did load
UITapGestureRecognizer *tapRecog = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(overlayDidTap:)];
[myOverLayView addGestureRecognizer:tapRecog];
- (void)overlayDidTap:(UITapGestureRecognizer *)gesture
{
//hide both overlay and table view here
}
Bad Approach
We should not add tap recogniser on main view itself. Because it may have lots of
controls inside of it. so when user tap on it. it will perform its operation. So to avoid
it we can simulate the same behaviour by above approach
You can get touch position by this:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[self.view addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
CGPoint touchPoint=[gesture locationInView:self.View];
}
Then just check if the point is in tableview frame. If not then hide the tableview. Hope this help. :)
Subclass UITableView, override pointInside:withEvent:. It is templated for this reason.
Something like:
-(BOOL)pointInside:(CGPoint) point withEvent:(UIEvent*) event
{
BOOL pointIsInsideTableView = [super pointInside:point withEvent:event];
BOOL pointIsOutsideTableView = // Some test
return pointIsInsideTableView || pointIsOutsideTableView;
}
So you can catch the touch in table view implementation, where it belongs logically in this case.

iOS: Tap Recognizer not consistent

I have a scenario like shown below
Right now, I am showing only 1 view with label 8. But I am planning to add 3 more such views to the HolderView.
The SmallerView/s are created from other Nib files.
I did this code for adding Tap Recognizer for ViewController's view
UITapGestureRecognizer *tapRecognizer=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapRecognized2:)];
[tapRecognizer setDelegate:self];
[self.view addGestureRecognizer:tapRecognizer];
Code for adding Tap Recognizer to the smaller views
I added smaller views to the HolderView. And assigned Tag IDs to them. After that,
for (SmallerView *view in HolderView.subviews) {
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapRecognized:)];
[recognizer setDelegate:self];
NSLog(#"Added gesture to the view with tag: %ld",view.tag);
[view addGestureRecognizer:recognizer];
}
3.
- (void)tapRecognized:(UITapGestureRecognizer *)paramSender
{
NSLog(#"tapped on %ld", paramSender.view.tag);
}
- (void)tapRecognized2:(UITapGestureRecognizer *)paramSender
{
NSLog(#"VC view");
}
I have enabled UserInteraction (both in code and Inspector) for all the views and UILabels on smaller views too.
The problem now is...
The smaller view's Tap recognisers are not really working consistently. Sometimes they print the output. All at suddenly it prints the ViewController's recogniser's output.
Please help
UPDATE:
Below is my View diagram.
Green Border: (In UIView's initWithFrame)d
self.layer.borderColor = [UIColor greenColor].CGColor;
Red Border:
MyTile *tile = [[[NSBundle mainBundle] loadNibNamed:#"View" owner:self options:nil] objectAtIndex:0];
self.myLabel.layer.borderColor=[UIColor redColor].CGColor;
Why that Green Border is coming only of that size? Shouldn't that be full square?
And, the gesture works only when I tap on the green area. Why?
It seems that you have a tap gesture recognizer on a view and also a tap gesture recognizer on its superview. The way gesture recognizers work is that, by default, both of them will be candidates to recognize the tap. If that is not what you want, it is up to you to prevent it.
You can:
set up a "you-go-first" relationship between the gesture recognizers, or
you can use their delegates to help decide between them, or
you can set up the subview so that it stops the superview's gesture recognizer from recognizing.
You have lots of options!
But if you do none of them, then both this view's gesture recognizer and its superview's gesture recognizer will be trying to recognize.
Perhaps a better solution would just to add one tapGestureRecognizer to the parent view.
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
tap.numberOfTapsRequired = 1;
tap.numberOfTouchesRequired = 1;
[tap addTarget:self action:#selector(handleTap:)];
[holderView addGestureRecognizer:tap];
Then add the target method
- (void) handleTap:(UITapGestureRecognizer *)tap {
UIView * holderView;
CGPoint tapPoint = [tap locationInView:holderView];
for (UIView * v in holderView.subviews) {
if (CGRectContainsPoint(v.frame, tapPoint)) {
// v is the subview that was pressed.
// add your code here.
break;
}
}
}
I have assigned a new frame to the frame which was having wrong borders. This helped in getting the gestures right.

how to place a subview on a cell so it does not block the tapgesture of its superview(cell)

I have the following code on a custom cell -
PSCollectionViewTapGestureRecognizer *gr = [[PSCollectionViewTapGestureRecognizer alloc] initWithTarget:self action:#selector(didSelectView:)];
gr.delegate = self;
[newView addGestureRecognizer:gr];
newView.userInteractionEnabled = YES;
how can i pass this gesture to its subviews? instead of adding a new gesture on subview.
currently the subview is blocking half of the view but tapping on it doesn't do anything.
needed to disable subviews interaction

how to get UILabel action in UITableView?

I have 3 UILabels in each cell of a table. I have added tap gesture recognisers to each one, but when it is tapped, how can I get the index path of the row that was tapped?
Here is my code
UILabel *tit_lbl=[[UILabel alloc]initWithFrame:CGRectMake(10,10,280,45)];
[tit_lbl setText:[[final_dictionaires_array objectAtIndex:indexPath.row] objectForKey:title]];
[tit_lbl setUserInteractionEnabled:YES];
[tit_lbl setTag:indexPath.row];
[btn addSubview:tit_lbl];
[tit_lbl release];
UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(goToArticleDetailsView:)];
[tit_lbl addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
With this, I can get the label action but I want to get which label is clicked in which Row ?? (I have 3 labels in each row).
I agree with the suggestions for using a button with a custom style instead of basically recreating buttons using labels and gesture recognisers. However, you'd still have the same problem. Which label was tapped? And which row of the table was it in?
You can find out which label was tapped by assigning tags to each one and then querying the view property of the gesture recogniser. The gesture recogniser will be the argument in your goToArticleDetailsView method:
-(void)goToArticleDetailsView:(id)sender
{
UITapGestureRecognizer *tapGR = (UITapGestureRecognizer*)sender;
if (tapGR.view.tag == 1)
// tapGR.view is the label that the gesture recognize was attached to
You can find out which row of the table was tapped using the gesture recogniser's locationOfTouch method, together with UITableView's indexPathForRowAtPoint: method:
CGPoint touchLocation = [tapGR locationOfTouch:0 inView:self.tableView];
NSIndexPath *tappedRow = [self.tableView indexPathForRowAtPoint:touchLocation];
A UILabel can not be clicked. You should use the UITextfield if you want to let the user to interact with the values.
To get the action you should sent a message to the instance of UITextField.
To get the right cell you can use the "indexPath"
good luck

Resources