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.
Related
My scenario is that there will be many sub views in the main view and tapping on each sub view should generate different result.
My approach is for each sub view to implement its own tap recognizer, instead of for the main view to have one single tap recognizer and calculate the which sub view's area the user has tapped in. Is this a correct and viable approach?
I have tried this approach but it doesn't seem to work. The tap method never gets called. I read lots of articles on stackoverflow but they didn't seem to help.
For example, although the sub view is not an image view I still manually set its userInteractionEnabled property to YES, as some posts suggested. But that didn't help.
Below is the main code of the sub view:
- (void) handleOneTap:(UITapGestureRecognizer*)paramSender{
// *** Never gets called
NSUInteger touchCounter = 0; for (touchCounter = 0;
touchCounter < paramSender.numberOfTouchesRequired;
touchCounter++){
CGPoint touchPoint = [paramSender locationOfTouch:touchCounter
inView:paramSender.view];
NSLog(#"Touch #%lu: %#",
(unsigned long)touchCounter+1, NSStringFromCGPoint(touchPoint));
}
}
- (void)viewDidLoad {
[super viewDidLoad];
_container = [[UIView alloc] initWithFrame:CGRectMake(20, 50, 280, 300)];
[self.view addSubview:_container];
_container.backgroundColor = [UIColor redColor];
_container.opaque = YES;
// setup tap recognizer
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleOneTap:)];
self.tapGestureRecognizer.numberOfTouchesRequired = 1;
self.tapGestureRecognizer.numberOfTapsRequired = 1;
self.view.userInteractionEnabled = YES;
self.container.userInteractionEnabled = YES;
[self.view addGestureRecognizer:self.tapGestureRecognizer];
}
Any help will be appreciated.
If you want to add UIGestureRecognizer to your subview, you should do it like that:
_container = [[UIView alloc] initWithFrame:CGRectMake(20, 50, 280, 300)];
[self.view addSubview:_container];
_container.backgroundColor = [UIColor redColor];
_container.opaque = YES;
_container.userInteractionEnabled = YES;
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleOneTap:)];
self.tapGestureRecognizer.numberOfTouchesRequired = 1;
self.tapGestureRecognizer.numberOfTapsRequired = 1;
self.view.userInteractionEnabled = YES;
[_container addGestureRecognizer:self.tapGestureRecognizer];
It looks like that problem is not in UITapGestureRecognizer, but in case how you add Subview from ViewController.
Right way to add subviewcontoller is:
SSubViewController *pvc = [SSubViewController controllerWithSubViewID:0];
[self.view addSubview:pvc.view];
[self addChildViewController:pvc];
Do it in your ViewController and it should solve your problem
I am using the following code to attach gesture recognizers to a custom view. But for some reason I am not able to get the gestures to work.
for(NSString *option in _options) {
UIView *blind = [self createBlind:option];
blind.userInteractionEnabled = YES;
blind.tag = index;
[self addSubview:blind];
[self addGravityBehaviorToBlind:blind];
[self addCollisionBehaviorToBlind:blind];
[self addElasticityBehaviorToBlind:blind];
[self registerGestureRecognizer:blind];
_spacingY += 44;
index++;
}
}
-(void) registerGestureRecognizer:(UIView *) blind {
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(blindTapped:)];
[blind addGestureRecognizer:tapGestureRecognizer];
}
-(void) blindTapped:(UITapGestureRecognizer *) recognizer { <-- THIS NEVER GETS CALLED
NSLog(#"blindTapped");
}
For some reason the blindTapped method never gets called even if I tap on the blind view.
UPDATE:
Yes, I see the views on the screen. The views (blind) is a subview in another view. The parent view gets added to the controller.view. There is no place where I have disabled interaction.
Here is the createBlind method:
-(UIView *) createBlind:(NSString *) option {
UIView *blind = [[UIView alloc] initWithFrame:CGRectMake(0, _spacingY, 200, 44)];
blind.layer.borderWidth = 1.0f;
blind.layer.borderColor = [UIColor whiteColor].CGColor;
UILabel *optionTitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, blind.bounds.size.width, blind.bounds.size.height)];
optionTitleLabel.text = option;
optionTitleLabel.font = [UIFont fontWithName:#"GillSans" size:17];
optionTitleLabel.textColor = [UIColor whiteColor];
optionTitleLabel.textAlignment = NSTextAlignmentCenter;
[blind addSubview:optionTitleLabel];
return blind;
}
I have removed all the gravity and UIKit methods but still I am not able to trigger the tap gesture.
SOLUTION:
When adding the custom view to my controller.view I was not setting the frame. Once the frame was setup everything worked.
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;
}
This is what I'm trying to do:
I want to start recognizing a gesture in a subview and then, when the finger leaves the subview, let the superview take over and handle the gesture. Is that possible?
At the moment, the view in which the gesture started "wins". Is there any way to "hand over" a gesture from one view to another "on the fly", without lifting the finger off the screen?
This is the code for a simple demo:
#implementation SPWKViewController {
UIView *_innerView;
UIPanGestureRecognizer *_outerGestureRecognizer;
UIPanGestureRecognizer *_innerGestureRecognizer;
UILabel *_label;
}
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [UIColor yellowColor];
_innerView = [[UIView alloc] initWithFrame:CGRectMake(50, 50, self.view.frame.size.width - 100, 200)];
_innerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_innerView.backgroundColor = [UIColor greenColor];
_label = [[UILabel alloc] initWithFrame:CGRectMake(0, 300, self.view.frame.size.width, 40)];
_label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_label.textAlignment = NSTextAlignmentCenter;
_label.backgroundColor = [UIColor clearColor];
[self.view addSubview:_innerView];
[self.view addSubview:_label];
}
- (void)viewDidLoad
{
[super viewDidLoad];
_outerGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[self.view addGestureRecognizer:_outerGestureRecognizer];
_innerGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handleGesture:)];
[_innerView addGestureRecognizer:_innerGestureRecognizer];
}
- (void)handleGesture:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
if (gestureRecognizer == _outerGestureRecognizer) {
_label.text = #"outer";
} else {
_label.text = #"inner";
}
} else {
_label.text = #"";
}
}
#end
Some background information: The actual problem I'd like to solve is this: I'd like to put a UIWebView inside of a UIScrollView. When I scroll to the bottom of the UIWebView, I want the parent UIScrollView to "take over" and keep scrolling without having to lift the finger off the screen first. I figured that in order to achieve that, I'd need to "hand over" the gesture from the UIWebView to the parent UIScrollView.
Thank you!
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