I have a button in my iPad app, when its pressed it addGestureRecognizer's. When pressed again, its supposed to remove them.
My code is in an if block, and I know the right block of code is runned because NSLog print the right log message.
I'm adding the recognizers like this:
[self.view addGestureRecognizer:panRecognizer];
[self.view addGestureRecognizer:pinchRecognizer];
[self.view addGestureRecognizer:rotationRecognizer];
[self.view addGestureRecognizer:tapRecognizer];
And trying to remove them like this:
[self.view removeGestureRecognizer:panRecognizer];
[self.view removeGestureRecognizer:pinchRecognizer];
[self.view removeGestureRecognizer:rotationRecognizer];
[self.view removeGestureRecognizer:tapRecognizer];
This is my whole function:
http://www.pastelib.com/show/ZlICyb9Q
It does not work and I cant figure out why, do you guys have any suggestions?
Thanks in advance for all the help and suggestions :)
Your GestureReconizers are declared locally to the -showMenu: method.
So each time your button is pressed, you create new GestureReconizers, so you didn't try to remove previous reconizers, but you try to remove newly created ones.
Change the scope of your reconizers objects, and your problem will be fixed.
Cheers.
Edit with code sample :
-(IBAction) showMenu:(id) sender {
if([self.view.subviews containsObject:menuView]) {
NSLog(#"remove gestures!");
// Dismiss menu
[menuView removeFromSuperview];
// Remove gestures
[self.view removeGestureRecognizer:panRecognizer];
[self.view removeGestureRecognizer:pinchRecognizer];
[self.view removeGestureRecognizer:rotationRecognizer];
[self.view removeGestureRecognizer:tapRecognizer];
}else{
// Create menu
NSLog(#"add gestures!");
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panDetected:)];
pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchDetected:)];
rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotationDetected:)];
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDetected:)];
tapRecognizer.numberOfTapsRequired = 2;
// Make gestures work simultaneously
panRecognizer.delegate = self;
pinchRecognizer.delegate = self;
rotationRecognizer.delegate = self;
// Set width and height if empty
self.menuController = [[menuController alloc] initWithNibName:#"menuController" bundle:nil];
if(screenWidth == 0) {
UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if(currentOrientation == 1 || currentOrientation == 2) {
// portrait
screenHeight = self.menuController.view.frame.size.height;
screenWidth = self.menuController.view.frame.size.width;
}else{
// Landscape
screenHeight = self.menuController.view.frame.size.width;
screenWidth = self.menuController.view.frame.size.height+20; //height+20px for the status bar
}
}
int menuHeight = 80;
self.menuController.view.frame = CGRectMake(0,screenHeight-(menuHeight-20), screenWidth, menuHeight);
self.menuView = self.menuController.view;
[self.menuController setDelegate:self];
[self addChildViewController:self.menuController];
[self.menuController didMoveToParentViewController:self];
[self.view addSubview:menuView];
// Add image gestures
[self.view addGestureRecognizer:panRecognizer];
[self.view addGestureRecognizer:pinchRecognizer];
[self.view addGestureRecognizer:rotationRecognizer];
[self.view addGestureRecognizer:tapRecognizer];
[self.view bringSubviewToFront:menuButton];
}
}
I did this in my project and it worked:
while (cellMainView.descripcionArticulo.gestureRecognizers.count) {
[cellMainView.descripcionArticulo removeGestureRecognizer:[cellMainView.descripcionArticulo.gestureRecognizers objectAtIndex:0]];
}
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 have code like this..
in loadView()
I have created the scrollview like this with no.of taps and max value
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.delegate = self;
self.scrollView.maximumZoomScale = 2;
self.scrollView.autoresizingMask = self.view.autoresizingMask;
[self.view addSubview:self.scrollView];
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[tapOnce setNumberOfTouchesRequired:1];
[doubleTap setNumberOfTapsRequired:2];
[tapOnce requireGestureRecognizerToFail:doubleTap];
[self.scrollView addGestureRecognizer:tapOnce];
[self.scrollView addGestureRecognizer:doubleTap];
Method implementation:
- (void) handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
//single tap in full screen mode it will dismiss the view
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer
{
//double tap will zoom the view to scrollview max value
[self.scrollView setZoomScale:self.scrollView.maximumZoomScale animated:NO];
}
Now I am able to "zoom" on tapping to full screen image and it will go in maxZoom value, but how to come back from zoomed to min value on double tap on the same, because I have functionality to dismiss the view on single tap. I need to handle one more double tap in the "handledoubleTap" method itself.
- (void)handleDoubleTap:(UIGestureRecognizer *)gestureRecognizer
{
if ( flag == 1 ){
flag = 0;
[self.scrollView setZoomScale:self.scrollView.maximumZoomScale animated:NO];
}
else {
flag = 1;
[self.scrollView setZoomScale:self.scrollView.minimumZoomScale animated:NO];
}
}
In the above method just set flag according to your need. Hope this helps.. :)
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.
When I click on a image I want to show another popover, but it doesn't work!
My handle Tap method looks like :
-(void)handleTapView:(UITapGestureRecognizer*)recognizer
{
CGPoint startPoint = [recognizer locationInView:recognizer.view];
NSLog(#"handle Tap VIEW!!!!!!!!");
if ([recognizer.view isKindOfClass:[UIImageView class]] ) {
NSLog(#"Tap Image!!!!!!!!");
}
else if ([self.popover isPopoverVisible]) {
[self.popover dismissPopoverAnimated:YES];
}
else {
ShapesListViewController *shapes = (ShapesListViewController*) [self.storyboard instantiateViewControllerWithIdentifier:#"ShapesListViewController"];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:shapes];
UIPopoverController *pop = [[UIPopoverController alloc] initWithContentViewController:nav];
shapes.delegate = self;
self.popover = pop;
CGRect popoverRect;
popoverRect.origin = startPoint;
popoverRect.size.width = 1;
popoverRect.size.height =1;
[pop presentPopoverFromRect:popoverRect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
}
In viewdidload :
ImageView *imgv = [[ImageView alloc] initWithImage:[UIImage imagNamed:#"delete.png"]];
imgv.center = CGPointMake(250,250);
[self.view addSubview:imgv];
ImageView *imgv2 = [[ImageView alloc] initWithImage:[UIImage imageNamed:#"gear.png"]];
imgv2.center = CGPointMake(400,400);
[self.view addSubview:imgv2];
//Tap Recognizer
self.singelTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapView:)];
[self.singelTapGestureRecognizer setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:self.singelTapGestureRecognizer];
You need to attach a separate gestureRecogniser to each view whose gestures you want to capture - in your case, both of your imageViews.
UITapGestureRecognizer *tapGR1, *tapGR2;
SEL selector = #selector(handleTapView:);
tapGR1 = [[UITapGestureRecognizer alloc] initWithTarget:self
action:selector];
tapGR2 = [[UITapGestureRecognizer alloc] initWithTarget:self
action:selector];
[imgv1 addGestureRecognizer:tapGR1];
[imgv2 addGestureRecognizer:tapGR2];
Don't attach a tapGR to their superview.
Then you also need to set userInteractionEnabled on each of the imageViews otherwise they will ignore touches (UIImageView defaults to userInteractionEnabled = NO):
imgv1.userInteractionEnabled = YES;
imgv2.userInteractionEnabled = YES;
In you handleTapView you need to reorganise slightly. Change the else if in you conditional sequence to if otherwise the third clause will never get triggered.
The recognizer.view for each of the recongnizers will correctly identify the imageView that was tapped. That will be the rect that the popover should present from in the coordinates of the imageView's superview - it's frame property.
So:
[pop presentPopoverFromRect:recognizer.view.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
In my app I have a tapGesture, panGesture, rotationGesture and pinchGesture.
The tapGesture is the starting point for all gestures, it shows me among other things which subview is selected.
After I entered a button to handle ImagePicker, the subview is still selected and therefore it is still handling gestures.
My question: Is there any statement to stop handling gestures?
EDIT
I don't need the gestureRecognizer, therefore I put them inactive:
panRecognizer.enabled = NO;
pinchRecognizer.enabled = NO;
rotationRecognizer.enabled = NO;
So if I need them I want to get them work when I am handling a tapRecognizer,
but here the recognizer do not move from inactive to active.
[panRecognizer isEnabled];
pinchRecognizer.enabled = YES;
rotationRecognizer.enabled = YES;
EDIT
My view is a ViewController and the subviews are on the imageView.
The recognizers are assigned to self.imageView.
In the first method I disenable the recognizers and in the second method I enable them
- (IBAction)photo: (id) sender {
panRecognizer.enabled = NO;
pinchRecognizer.enabled = NO;
rotationRecognizer.enabled = NO;
UIImagePickerController* picker = [[UIImagePickerController alloc]init];
picker.delegate = self;
picker.allowsEditing = NO;
#try {
picker.sourceType=UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:picker animated:YES];
}
#catch (NSException * e) {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Error" message:#"Camera is not available"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alert show];
}
[picker release];
}
- (IBAction)oneTap: (UIGestureRecognizer*)gestureRecognizer {
NSLog(#"oneTap");
float differenz = 2000;
[panRecognizer isEnabled];
pinchRecognizer.enabled = YES;
rotationRecognizer.enabled = YES;
for (UIView* const subview in array) {
subview.opaque = YES;
CGPoint const point = [gestureRecognizer locationInView:self.imageView];
float zwischenS = sqrt(powf(point.x - subview.frame.origin.x,2)) + sqrt(powf(point.y - subview.frame.origin.y,2));
if (differenz > zwischenS ) {
differenz = sqrt(powf(point.x - subview.frame.origin.x,2)) + sqrt(powf(point.y - subview.frame.origin.y,2));
newView.layer.borderColor = [[UIColor clearColor]CGColor];
newView = subview;
subview.layer.borderColor = [[UIColor whiteColor]CGColor];
subview.layer.borderWidth = 3.0f;
[imageView bringSubviewToFront: subview];
}
}
}
What is my mistake?
Thanks in advance
property [UIGestureRecognizer enabled]
//YOU CREATE GESTURES LIKE THIS
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc]
initWithTarget:self action:#selector(handlePanGesture:)];
//YOU ADD THEM LIKE THIS
[self.view addGestureRecognizer:panGesture];
//AND YOU REMOVE THEM LIKE THIS
[self.view removeGestureRecognizer:panGesture];
I'm not sure how you are coding things, but I hope this gives you an idea