I have several IBActions attached to UIButtons. The IBActions work fine until I add the following code:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"View Did Load");
[self addGestureRecognizersToView:drawImage];
}
After I add that chunk of code the IBActions do not fire. The UIButtons highlight when I touch them, but none of the IBAction code gets hit.
Here is my addGestureRecognizers code:
- (void)addGestureRecognizersToView:(UIImageView *)theView {
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[panGesture setMaximumNumberOfTouches:2];
[panGesture setMinimumNumberOfTouches:1];
//panGesture.delegate = drawImage;
[theView addGestureRecognizer:panGesture];
[panGesture release];
UITapGestureRecognizer *doubleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleFingerTap setNumberOfTapsRequired:2];
[self.view addGestureRecognizer:doubleFingerTap];
[doubleFingerTap release];
UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[singleFingerTap setNumberOfTapsRequired:1];
[self.view addGestureRecognizer:singleFingerTap];
[singleFingerTap release];
}
If I comment out the singleFingerTap code it works. I'm guessing I should not be using alloc since I have already alloced that once before in doubleFingerTap?
Any ideas on what I might be missing here?
You single finger tap is hindering with the normal behavior of the button. You will have to make sure the touches get through unhindered.
[singleFingerTap setCancelsTouchesInView:NO];
It sounds like the UITapGestureRecognizer is intercepting the taps that would otherwise have been handled by the UIButtons.
You can use gestureRecognizer:shouldReceiveTouch::
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return (touch.view != self.button1 &&
touch.view != self.button2);
}
Alternatively, you could hack the responder chain.
Related
I am working on an application which works like a remote control of different devices like Game Console, Set-top Box, etc.
Application contains different type of controls like gesture and buttons to perform events as remote.
Single gesture view contains multiple gesture recognizer as follow:
1 finger Tap using UITapGestureRecognizer
2 finger Tap using UITapGestureRecognizer
1 finger swipe using UISwipeGestureRecognizer
2 finger swipe using UISwipeGestureRecognizer
My requirement is to implement 1 finger Swipe gesture recognizer along with hold event. So, that will continue my swipe action until user will not remove its finger from the view.
I have tried UILongPressGestureRecognizer after UISwipeGestureRecognizer but this didn’t work for me because it is executing along with Swipe movement. And I want this after Swipe end, but finger will not remove.
My code snippet :
-(void) gestureView:(UIView*)viewGesture {
UISwipeGestureRecognizer *swipeGestureSingleRight;
UISwipeGestureRecognizer *swipeGestureSingleLeft;
UISwipeGestureRecognizer *swipeGestureSingleUp;
UISwipeGestureRecognizer *swipeGestureSingleDown;
swipeGestureSingleUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeGestureSingle_Handle:)];
[swipeGestureSingleUp setDelegate:self];
[swipeGestureSingleUp setDirection:(UISwipeGestureRecognizerDirectionUp)];
[swipeGestureSingleUp setNumberOfTouchesRequired:1];
[viewGesture addGestureRecognizer:swipeGestureSingleUp];
swipeGestureSingleDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeGestureSingle_Handle:)];
[swipeGestureSingleDown setDelegate:self];
[swipeGestureSingleDown setDirection:(UISwipeGestureRecognizerDirectionDown)];
[swipeGestureSingleDown setNumberOfTouchesRequired:1];
[viewGesture addGestureRecognizer:swipeGestureSingleDown];
swipeGestureSingleRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeGestureSingle_Handle:)];
[swipeGestureSingleRight setDelegate:self];
[swipeGestureSingleRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
[swipeGestureSingleRight setNumberOfTouchesRequired:1];
[viewGesture addGestureRecognizer:swipeGestureSingleRight];
swipeGestureSingleLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeGestureSingle_Handle:)];
[swipeGestureSingleLeft setDelegate:self];
[swipeGestureSingleLeft setDirection:(UISwipeGestureRecognizerDirectionLeft)];
[swipeGestureSingleLeft setNumberOfTouchesRequired:1];
[viewGesture addGestureRecognizer:swipeGestureSingleLeft];
longPressGestureOnSwipe = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(longPressGesture_Handle:)];
longPressGestureOnSwipe.minimumPressDuration = 0.03;
longPressGestureOnSwipe.delegate = self;
[viewGesture addGestureRecognizer:longPressGestureOnSwipe];
isSwipeEnd = false;
[longPressGestureOnSwipe setEnabled:isSwipeEnd];
}
- (void)swipeGestureSingle_Handle:(UISwipeGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
singleTouchSwipeSenderDirection = sender.direction;
isSwipeEnd = true;
[longPressGestureOnSwipe setEnabled:isSwipeEnd];
}
}
-(void)longPressGesture_Handle:(UILongPressGestureRecognizer*)sender {
if (sender.state == UIGestureRecognizerStateEnded) {
isSwipeEnd = false;
[longPressGestureOnSwipe setEnabled:isSwipeEnd];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
if (isSwipeEnd) {
[super touchesBegan:touches withEvent:event];
} else {
return;
}
}
Please suggest me correction or solution for my requirement.
Thanks in advance!
I have drawingView and listen UIPanGestureRecognizer, UIRotationGestureRecognizer, and UIPinchGestureRecognizer on it.
- (void)viewDidLoad
{
[super viewDidLoad];
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panDetected:)];
[self.drawingView addGestureRecognizer:panRecognizer];
UIRotationGestureRecognizer *rotateRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotateRecognizer:)];
[self.drawingView addGestureRecognizer:rotateRecognizer];
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchRecognizer:)];
[self.drawingView addGestureRecognizer:pinchRecognizer];
[self.drawingView reloadData];
}
-(void) pinchRecognizer:(UIPinchGestureRecognizer*) recognizer {
return;
NSLog(#"Call scale");
}
- (void)rotateRecognizer:(UIRotationGestureRecognizer*)recognizer {
NSLog(#"Call rotaion");
}
If i only choose UIRotationGestureRecognizer or UIPinchGestureRecognizer it is perfect. But if using UIRotationGestureRecognizer and UIPinchGestureRecognizer only UIPinchGestureRecognizer called, UIRotationGestureRecognizer isn't called.
What is problem in my code?
I think i will make a UISegmented to choose mode , UIRotationGestureRecognizer or UIPinchGestureRecognizer, what should i do?
Thank a lot
If you want to have multiple gestures recognized at once, try using gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer, ex:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Edit: In addition to including the delegate in your .h, make sure to set your UIGestureRecognizer's delegate's to self, ex:
UIPanGestureRecognizer *panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panDetected:)];
panRecognizer.delegate = self;
[self.drawingView addGestureRecognizer:panRecognizer];
UIRotationGestureRecognizer *rotateRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotateRecognizer:)];
rotateRecognizer.delegate = self;
[self.drawingView addGestureRecognizer:rotateRecognizer];
Use requireGestureRecognizerToFail: to recognize the gesture if the other gesture recognizer did not executes.
[rotateRecognizer requireGestureRecognizerToFail: pinchRecognizer];
Today I tried to add an additional UILongPressGestureRecognizer to an UISwitch, which did not really work. My code is the following:
UILongPressGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(doSomething:)];
[lpgr setDelaysTouchesBegan:YES];
[lpgr setDelaysTouchesEnded:YES];
[lpgr setCancelsTouchesInView:YES];
[self.switcher addGestureRecognizer:lpgr];
in the viewDidLoad method of the viewController that is the parent viewController of that switch. (the switcher is an instance variable, set through a storyboard. The IBOutlet is set properly from the UISwitch to the switcherProperty of its viewController).
On a couple of other controls (like a UIButton, UISlider, UIStepper and so on) this works, even without the touches cancelled or delayed, and perfectly triggers the target method. However, with my switch, it refuses that behavior.
I have tried removing any other gestureRecognizer on the UISwitch by iterating through all gestureRecognizers on that switch and calling [switcher removeGestureRecognizer: ... ], I´ve also set all of them to require my longPressGestureRecognizer to fail. Other types of gestureRecognizers don´t fire as well.
As far as I understand, GestureRecognizers will receive touches, before the view or control, which they belong to, receives them. Thus, setCancelsTouchesInView:YES and setDelaysTouchesInView:YES should enable the gestureRecognizer to handle every single gesture until it fails or succeeds, without the view knowing, right?
--------------EDIT------------------
The whole content of my method:
- (void)viewDidLoad
{
[super viewDidLoad];
UIGestureRecognizer *lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.view addGestureRecognizer:lpgr];
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.button addGestureRecognizer:lpgr];
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.slider addGestureRecognizer:lpgr];
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.segmentedControl addGestureRecognizer:lpgr];
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.switcher addGestureRecognizer:lpgr];
lpgr = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(edit:)];
[self.stepper addGestureRecognizer:lpgr];
}
As I said, for the other controls this is working, only the switch does not want to work
try with it
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// Disallow recognition of tap gestures in the segmented control.
if ((touch.view == yourSwitch)) {//change it to your condition
return NO;
}
return YES;
}
make sure you confirm UIGestureRecognizerDelegate for it to work.
I am adding a UITapGestureRecognizer to my application to detect a double tap gesture.
UITapGestureRecognizer *tapgr = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTapGesture:)];
tapgr.numberOfTaps = 2;
tapgr.delegate = self;
[_view addGestureRecognizer:tapgr];
[tapgr release];
This is working fine unless I show a tooltip in my application. They are set up like this:
[_view.toolTipView addTarget:self action:#selector(handleTap:) forControlEvents:UIControlEventTouchUpInside];
Before the introduction of my gesture recognizer, these tooltips where clickable and reacted, now they aren't reacting anymore...
How can I make a gesture recognizer and a standard UIControlEventTouchUpInside-Setup work together?
I found a solution:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (gestureRecognizer == tapgr) {
return ![touch.view isKindOfClass:[UIControl class]];
}
return YES;
}
This method prevents the GestureRecognizer from being fired when a UIControl (i.e. Button) is pressed.
if you want the _view can respond single tap and Double tap together, you can try this
UITapGestureRecognizer * singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
UITapGestureRecognizer * doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleDoubleTap:)];
[doubleTap setNumberOfTapsRequired:2];
//Add this code to disable double tap and only responds to single tap when user tap the _view just once time
[singleTap requireGestureRecognizerToFail:doubleTap];
[self addGestureRecognizer:doubleTap];
[self addGestureRecognizer:singleTap];
[singleTap release];
[doubleTap release];
if you want to use TouchEvent try UIControlEventTouchDownRepeat
[button addTarget:self actionselector(multipleTap:withEvent:) forControlEvents:UIControlEventTouchDownRepeat];
//Try to check wheather is doulbe tap or single tap.
-(IBAction)multipleTap:(id)sender withEvent:(UIEvent*)event {
UITouch* touch = [[event allTouches] anyObject];
if (touch.tapCount == 2) {
// do action.
}
}
You can't do that. I think you should choose another way to implement that.
I'm having trouble just turning on gesture recognizers in my code. I added a handleTap callback to to the tap gesture recognizer but the print statement never happens. I'm just not having any luck. Does anyone see what I'm doing wrong here?
In my ViewController.h
#interface ViewController : UIViewController<UITextFieldDelegate, UIGestureRecognizerDelegate> {
}
#end
This is what I have in my ViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame];
View *myview = [[View alloc] initWithFrame:applicationFrame];
myview.userInteractionEnabled = YES;
myview.multipleTouchEnabled = YES;
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleTap)];
tap.numberOfTapsRequired = 1;
tap.delegate = self;
[myview addGestureRecognizer:tap];
self.view = myview;
}
-(void)handleTap:(UITapGestureRecognizer*)recognizer {
NSLog(#"dismiss keyboard");
//[usernameTextField resignFirstResponder];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
Edit: I added a text field and when I click on the text field I see the tap selector print statement. But if I tap off the text field I don't get the selector print statement.
I think the problem is with your selector. Try changing
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleTap)];
And replace it with
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleTap:)];
To make the selector match the signature for handleTap.
You are passing the wrong selector when initialising.
The line should read like this:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(handleTap:)];
Notice the colon after handleTap to match the method you want to use.
Apparently subclassing the UIView and overriding drawrect with an empty function caused the selector to be called.