Add a gesture recognizer to tableView header doesn't work? - ios

I know that a "table view header"(the most top-part of a table view) is a View
So I try to add a UITapGestureRecognizer to it ,but it doesn't work...
code is simple :
- (void)tap:(UITapGestureRecognizer *)recognizer
{
// do something
}
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[self.tableView.tableHeaderView addGestureRecognizer:recognizer];
Any tips here to care ? thanks a lot

Here's the thing that works for me:
Instead adding this:
self.tableView.tableHeaderView
I add gesture recognizer on every UILabel on tableview.
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UILabel *headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [UIColor greenColor];
headerLabel.text = [NSString stringWithFormat:#"Header No.%d",section];
headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(catchHeaderGesture:)];
tapGesture.cancelsTouchesInView = NO;
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
//return nil;
}
-(void)catchHeaderGesture:(UIGestureRecognizer*)sender
{
UILabel *caughtLabel = (UILabel*)sender.view;
NSLog(#"header no : %d", caughtLabel.tag);
}
I hope that helps.

First of all
Make sure that you call this code section in viewDidLoad or viewWillAppear
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[self.tableView.tableHeaderView addGestureRecognizer:recognizer];
Second, please make sure that
self.tableView.tableHeaderView
is not null, add
NSLog([self.tableView.tableHeaderView description]);
And check the console for output
I just tried your code and the tap was recieved correctly

Related

UITapGesture Selector for UILabel issue

I added tapGesture for self.view and UILabel (subview of mainView), each performs different selectors.
But the only main view tapGesture is being called and label tapgesture is not being called. How it is handled?
Here is the code:
UITapGestureRecognizer *tapGesForSelf = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForSelf:)];
[self.view addGestureRecognizer:tapGesForSelf];
UITapGestureRecognizer *tapLblClick = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForLbl:)];
[lbl addGestureRecognizer:tapLblClick];
For two selectors only one method is called tapGesForSelf.
Here lbl is the subview of self.view.
Try this
- (void)viewDidLoad {
[super viewDidLoad];
[_lbl setUserInteractionEnabled:YES];
UITapGestureRecognizer *tapGesForSelf = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForSelf:)];
[self.view addGestureRecognizer:tapGesForSelf];
UITapGestureRecognizer *tapLblClick = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesForLbl:)];
[_lbl addGestureRecognizer:tapLblClick];
[tapGesForSelf requireGestureRecognizerToFail:tapLblClick];
}
- (void)tapGesForSelf:(UITapGestureRecognizer *)gesture
{
NSLog(#"self");
}
- (void)tapGesForLbl:(UITapGestureRecognizer *)gesture
{
NSLog(#"label");
}
I post answer for your question now once I tried and it worked well.
First see the label in design.I set label text as "Tap Me"
Now I set the code for view and label
- (void)viewDidLoad
{
[super viewDidLoad];
//TapGesture for Label
UITapGestureRecognizer *tapLabel = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionTapLabel:)];
tapLabel.delegate = self;
tapLabel.numberOfTapsRequired = 1;
lblTapMe.userInteractionEnabled = YES;
[lblTapMe addGestureRecognizer:tapLabel];
//TapGesture for View
UITapGestureRecognizer *tapMainView = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(actionTapMainView:)];
tapMainView.delegate = self;
tapMainView.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapMainView];
}
//Action method for Label
-(void)actionTapLabel:(UITapGestureRecognizer *)gestureOnLabel{
UILabel *label = (UILabel *)gestureOnLabel.view;
NSLog(#"Lable text is - %#",label.text);
}
//Action method for View
-(void)actionTapMainView:(UITapGestureRecognizer *)gestureOnMainView{
NSLog(#"The Main view is tapped");
}
Output Screenshot
Please setUserInteractionEnabled:YES for interact the TapGesture
[lbl setUserInteractionEnabled:YES];

View added manually in code does not appear

Once user double taps on image/screen, it adds an annotation on the screen. When it adds annotation image, I want also open a subview to add annotation detail. However, my subview does not come up.
Here is my code snippet.
#synthesize iViewController;
- (void)viewDidLoad {
[super viewDidLoad];
// adding gesture recognizer
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
tapGesture.numberOfTapsRequired = 2;
[self.imvPhoto addGestureRecognizer:tapGesture];
tapGesture.delegate = self;
}
- (void)handleTapGesture:(UITapGestureRecognizer *)sender {
if (sender.state == UIGestureRecognizerStateRecognized) {
// Here is the code for subview adding
iViewController = [[InventoryViewController alloc] init];
[self.view addSubview:iViewController.view];
iViewController.view.frame = CGRectMake(100, 100, 320, 460);
}
}
Based on #rdelmar feedback, here is the solution:
iViewController = (InventoryViewController *)[self.storyboardinstantiateViewControllerWithIdentifier:#"InventoryViewController"];
iViewController.view.frame = CGRectMake(728, 32, 300, 736);
[self.view addSubview:iViewController.view];

can a titleView be made to accept tap gestures?

In a custom class MMTimerButton, I set up the button to respond to a single and a double tap
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self setBackgroundColor: [UIColor clearColor]];
UITapGestureRecognizer *singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
singleTapRecognizer.numberOfTapsRequired=1;
singleTapRecognizer.delaysTouchesEnded=YES;
UITapGestureRecognizer *doubleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTapRecognizer.numberOfTapsRequired=2;
[singleTapRecognizer requireGestureRecognizerToFail: doubleTapRecognizer];
[self addGestureRecognizer:singleTapRecognizer];
[self addGestureRecognizer:doubleTapRecognizer];
}
return self;
}
I implement the two methods like this in the same file
-(void)handleTap:(UITapGestureRecognizer *)sender{
NSLog(#"single tap");
}
-(void)handleDoubleTap:(UITapGestureRecognizer *)sender{
NSLog(#"double tap");
}
In the header, I declare two methods
#import <UIKit/UIKit.h>
#interface MMTimerButton : UIButton
-(void)handleTap:(UITapGestureRecognizer *)sender;
-(void)handleDoubleTap:(UITapGestureRecognizer *)sender;
In the storyboard, I added a button to the interface and set its custom class to be MMTimerButton.
Nothing's happening when I click the button (in the simulator). One click, two click, both nothing.
I also tried doing it without a button, just adding gesture recognizers to the titleView. Nothing happens when I click on the title in the simulator
UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : #selector (handleDoubleTap:)];
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : #selector (handleSingleTap:)];
[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];
[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];
self.navigationItem.title =#"title";
[self.navigationItem.titleView addGestureRecognizer:doubleTap];
[self.navigationItem.titleView addGestureRecognizer:singleTap];
However, when I add this code to header view, it works fine (in the simulator)
-(UIView*)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UILabel *headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [UIColor clearColor];
headerLabel.text = [NSString stringWithFormat:#"0:00",section];
headerLabel.textAlignment = UITextAlignmentCenter;
headerLabel.frame=CGRectMake(10,-5,tableView.frame.size.width,41);
UITapGestureRecognizer* doubleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : #selector (handleDoubleTap:)];
UITapGestureRecognizer* singleTap = [[UITapGestureRecognizer alloc] initWithTarget : self action : #selector (handleSingleTap:)];
[singleTap requireGestureRecognizerToFail : doubleTap];
[doubleTap setDelaysTouchesBegan : YES];
[singleTap setDelaysTouchesBegan : YES];
[doubleTap setNumberOfTapsRequired : 2];
[singleTap setNumberOfTapsRequired : 1];
self.navigationItem.title =#"title";
[headerLabel addGestureRecognizer:doubleTap];
[headerLabel addGestureRecognizer:singleTap];
return headerLabel;
//return nil;
}
You are showing a lot of troubled code here, so it's hard to know where to start.
In the case of your initWithFrame:, the problem is that this method is never called for a button. Moreover, you've got a conflict because the button already contains the ability to respond to a tap, internally (it's a button!).
In the second set of code, you never set the titleView to a view, so it is nil, and your code does nothing. Also, you can't set both the title and the titleView (you are setting the title).
The answer to your title question is, of course a titleView can respond to a tap. Lots of apps do this (including mine).
Also, you do not need your requireGestureRecognizerToFail - a single tap gesture recognizer and a double tap gesture recognizer already know how to mediate between themselves.
So basically my advice would be: stop over-complicating everything. Don't make big assumptions and dive in. Start with stuff that you know works and take little steps. Test everything with logging / breakpoints as you go, to see that what's happening is what you imagine.

selector function not called when adding list of image views with tap gesture recognizer

I have trouble with creating list of ImageViews with tap gesture. When I create gesture, selector function is not called. When I create only one imageView function is called. Any idea why? It is all subview of a large scroll view.
This is my code:
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTaped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
for(int k=0;k<MyList.count;k++){
for(int i=0;i<listSize;i++){
UIImageView *clickForDetail =[[UIImageView alloc]initWithFrame:CGRectMake(i*HELLO_WIDTH,k*LIST_ROW_HEIGH ,HELLO_WIDTH, LIST_ROW_HEIGH)];
clickForDetail.backgroundColor = [UIColor clearColor];
clickForDetail.tag = tag;
clickForDetail.userInteractionEnabled = YES;
[clickForDetail addGestureRecognizer:singleTap];
[myScroll addSubview:clickForDetail];
tag++;
}
}
and selector function:
-(void)imageTaped: (UITapGestureRecognizer *)recognizer
{
NSLog(#"single Tap on imageview");
}
Is it possible somehow to get tag of a ImageView that is clicked?
You need to put different tap gesture for each view object
for(int k=0;k<MyList.count;k++){
for(int i=0;i<listSize;i++){
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTaped:)];
singleTap.numberOfTapsRequired = 1;
singleTap.numberOfTouchesRequired = 1;
UIImageView *clickForDetail =[[UIImageView alloc]initWithFrame:CGRectMake(i*HELLO_WIDTH,k*LIST_ROW_HEIGH ,HELLO_WIDTH, LIST_ROW_HEIGH)];
clickForDetail.backgroundColor = [UIColor clearColor];
clickForDetail.tag = tag;
clickForDetail.userInteractionEnabled = YES;
[clickForDetail addGestureRecognizer:singleTap];
[epgScroll addSubview:clickForDetail];
tag++;
}
}
-(void)imageTaped: (UITapGestureRecognizer *)recognizer
{
NSLog(#"single Tap on imageview");
UIImageView *selectedTextView = (UIImageView *)recognizer.view;
}

Touch detection on UILabel inside UIScrollView

I have a UIScrollView and inside this I have UILabels. I need to detect touch events for the UILabels. At the moment, it is detecting the touch inside the second label only. It ignores the first.
I have the code -
Creating the UIScrollView
backGroundView = [[UIScrollView alloc] init];
backGroundView.frame= self.view.frame;
backGroundView.userInteractionEnabled = YES;
[backGroundView setScrollEnabled:YES];
backGroundView.showsVerticalScrollIndicator = YES;
backGroundView.contentSize = CGSizeMake(self.view.frame.size.width, self.view.frame.size.height);
backGroundView.delegate = self;
[self.view addSubview:backGroundView];
Creating the UILabel
UILabel *OneDay = [[UILabel alloc] initWithFrame:CGRectMake(15, stockChart.bounds.origin.y + stockChart.bounds.size.height + 35, 40, 30)];
OneDay.text = #"1d";
OneDay.tag = 1;
OneDay.userInteractionEnabled = YES;
OneDay.layer.borderColor = [UIColor grayColor].CGColor;
OneDay.layer.borderWidth = 1.0f;
OneDay.textAlignment = UITextAlignmentCenter;
[OneDay addGestureRecognizer:detectTimeFrameChange];
[backGroundView addSubview:OneDay];
UILabel *FiveDay = [[UILabel alloc] initWithFrame:CGRectMake(45, stockChart.bounds.origin.y + stockChart.bounds.size.height + 35, 40, 30)];
FiveDay.text = #"5d";
FiveDay.tag = 2;
FiveDay.userInteractionEnabled = YES;
FiveDay.layer.borderColor = [UIColor grayColor].CGColor;
FiveDay.layer.borderWidth = 1.0f;
FiveDay.textAlignment = UITextAlignmentCenter;
[FiveDay addGestureRecognizer:detectTimeFrameChange];
[backGroundView addSubview:FiveDay];
Creating the gesturerecognizer
UITapGestureRecognizer *detectTimeFrameChange = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(timeFrameLabelTapped:)];
detectTimeFrameChange.numberOfTapsRequired = 1;
[backGroundView addGestureRecognizer:detectTimeFrameChange];
Handling gesture
-(void)timeFrameLabelTapped:(UITapGestureRecognizer*)recognizer{
if (recognizer.view.tag == 1) {
NSLog(#"One pressed");
}
else if (recognizer.view.tag == 2){
NSLog(#"2 pressed");
}
}
You can use this :
UITapGestureRecognizer *labelTap=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(labelTapped)];
labelTap.numberOfTapsRequired=1;
[yourLabel addGestureRecognizer:labelTap];
handle the touch tap event inside labelTapped method:
-(void)labelTapped
{
//your code to handle tap
}
Touch events are not detected on UIScrollview for getting your requirement add tap gestures to your label.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured)];
[OneDay addGestureRecognizer:singleTap];
-(void)singleTapGestureCaptured{
NSLog(#"touch detected");
}
You can find using tapgesturerecogniser like that...
UITapGestureRecognizer *singleFingerTap =
[[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(handleSingleTap:)];
[self.scrollview addGestureRecognizer:singleFingerTap];
//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
if(recognizer.view.tag == 1){}
//Do stuff here...
}
Where have you written the touchesBegan?
If you want to detect the touches in the label you'll have to create a subclass of label and write your touchesBegan there to detect the touch events
The problem here is that you are trying to use the same gesture recognizer for multiple views. A gesture recognizer can only be attached to a single view at once. You are only receiving events from the last view, because that is the view the recognizer is currently attached to. To fix the issue, simply create a gesture recognizer for each view you want to detect touches in.

Resources