prevent touchdown IBAction event from firing when UITapGestureRecognizer fires on double tap - iphone

I have two IBActions applied to a button one of which fires on touchdown and down and the other on touch up, however I also have a tap gesture applied to the button that fires on a double tap.
I've applied NSLog to see whats happening and the result is that both the touchdown and double tap fire when I double tap (fortunately the touch up doesn't fire) which makes sense - but how do i prevent the touch down firing when I double tap?
Code example
//fired on touch down
-(IBAction)touchdown:(id)sender
{
NSLog(#"touching down.");
}
//fired on touch up
-(IBAction)touchup:(id)sender
{
NSLog(#"taking off.");
}
//fired on double click
-(IBAction)boost:(UITapGestureRecognizer *)sender
{
NSLog(#"goodbye.");
}

Import the delegate, <UIGestureRecognizerDelegate>
I think you done this in viewDidLoad Method,
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(boost:)];
tapGestureRecognizer.delegate = self;
tapGestureRecognizer.numberOfTapsRequired = 2;
[self.button addGestureRecognizer:tapGestureRecognizer];
You need to implement this delegate method, based on your touch down coordinates,
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
CGPoint coords = [touch locationInView:self.button];
NSLog(#"Coords: %g, %g", coords.x, coords.y);
if (coords.y < 21 && coords.y > 25)
return NO;
else
return YES;
}

Related

how to get touch event after a button click in iphone?

I have a UIButton in my project and after a button click I am showing a UIView on the top of that button in such a way that the button remains hidden that time. I want to get a touchesmoved event on that time when I keep that button pressed and move finger over the overlapped UIView. As far as I did is like the following:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch view] == uiview)
{
NSLog(#"Touches moved");
}
but it doesnt get called when I keep the button pressed that is hidden when the UIView comes up and the uiview goes hidden when I release the button. Any suggestion please?
I don't quiet understand what your trying to do but I would suggest you use UIGestureRecognizers and add Gestures Recognizers to your button.
Try using this code. I've used this in a card game i developed. moving cards around using long press gestures. Hope i helps.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(addLongpressGesture:)];
[longPress setDelegate:self];
[YOUR_BUTTON addGestureRecognizer:longPress];
- (void)addLongpressGesture:(UILongPressGestureRecognizer *)sender {
UIView *view = sender.view;
CGPoint point = [sender locationInView:view.superview];
if (sender.state == UIGestureRecognizerStateBegan){
// GESTURE STATE BEGAN
}
else if (sender.state == UIGestureRecognizerStateChanged){
//GESTURE STATE CHANGED/ MOVED
CGPoint center = view.center;
center.x += point.x - _priorPoint.x;
center.y += point.y - _priorPoint.y;
view.center = center;
// This is how i drag my views
}
else if (sender.state == UIGestureRecognizerStateEnded){
//GESTURE ENDED
}
You need to set view.userInteractionEnabled = NO for your overlapped UIView.
This will send action to button.

My button wont stay highlighted when I add a pan gesture recognizer?

I added a UIPanGestureRecognizerto my UIButton. And now my when I drag a short distance with my finger after I pressed the button, the button stops being highlighted. Normally, a UIButton will stay highlighted unless you drag pretty far outside the UIButtons frame. However, with a pan gesture recognizer, now even if I drag a little bit, the button stops being highlighted.
Nothing in my code sets the buttons highlighted property to no. I even tried erasing all the code in my panning gesture recognizers action selector thing(the method that gets called whenever i pan on my button).
I also tried setting the button's highlighted property to NO in the panning gesture recognizer's action selector thing.
This kind of worked its just the highlightedness flashes. When you pan the highlighted goes away then comes back really fast, like a flash. So, this doesnt work too. Any ideas?
Gestures, by default, will cancel the touches in the views that they are linked to. So, when the touches in your button get cancelled it becomes unhighlighted. To prevent this behavior, set the cancelsTouchesInView property of your gesture to NO.
This will work
-(void) panDetected:(UIGestureRecognizer *) gesture
{
if(gesture.state == UIGestureRecognizerStateBegan)
{
yourButton.backgroundImageView.image = [UIImage imageNamed:#"your_button_highlited_image.png"];
}
else if(gesture.state == UIGestureRecognizerStateChanged)
{
}
else if(gesture.state == UIGestureRecognizerStateEnded)
{
yourButton.backgroundImageView.image = [UIImage imageNamed:#"your_button_normal_image.png"];
}
}
I have experienced the same problem. borrrden is right; to fix it, set the viewController the delegate for the gestureRecognizer, and cancel the touch if the touch is on a IUButton. First add the protocol `UIGestureRecognizerDelegate on the .h file. Then, after creating the gesture recognizer, set the view controller as its delegate:
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(aMethod)];
gestureRecognizer.delegate = self;
[self.view addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
Finally override shouldReceiveTouchand cancel unwanted touches:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
if ([touch.view isKindOfClass:[UIButton class]]) { //Do not override UIButton touches
return NO;
}
return YES;
}

iPhone iOS how to make UIScrollView work with UIRotationGestureRecognizer when zooming is enabled?

I'm working in iOS5, and apparently I should be able to control or at least subdue the UIScrollView's internal pinch gesture recognizer using scrollView.pinchGestureRecognizer.
However, my code does not seem to work. The recognizer does not treat my class as a delegate and does not wait for my rotation gesture recognizer to fail. What can I do to make the rotation gesture a priority, after which the pinch would be considered?
More precisely, the issue that I'm running in is that the view that is being rotated and zoomed at the same time "flies off the screen" towards the bottom left corner, never to be seen again.
-(void)setup scrollViews
{
[tempScrollView.pinchGestureRecognizer requireGestureRecognizerToFail:rotationRecognizer];
tempScrollView.pinchGestureRecognizer.delegate = self;
tempScrollView.maximumZoomScale = 4.0;
tempScrollView.minimumZoomScale = 0.25;
//
tempScrollView.delegate = self;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
if([gestureRecognizer isEqual:rotationRecognizer])
{
NSLog(#"Rotation gesture");
}else {
NSLog(#"Other gesture: %#", [gestureRecognizer class]);
}
return YES;
}
- (IBAction)rotateView:(id)sender {
if([sender isKindOfClass:[UIRotationGestureRecognizer class]])
{
UIRotationGestureRecognizer* recognizer = sender;
float recognizerRotation = [recognizer rotation];
CGAffineTransform transform = CGAffineTransformMakeRotation(recognizerRotation);
activeView.transform = transform;
}
}
As far as I know, the pinchGestureRecognizer in UIScrollView is read only.
However, you might try to subclass UIScrollView and override the method addGestureRecognizer: to disable the pinchGestureRecognizer, then add your own custom pinchGestureRecognizer.

How to cancel UIGestureRecognizer if subview's button pressed

I am struggling to get the behaviour I would like from the gesture recognisers, specifically cancelling certain gestures if others have fired.
I have a scrollView set to paging and multiple subviews in each page. I have added a touch gesture recogniser to scroll to the next or prev page if the user taps to the right or left of the page.
// Add a gesture recogniser turn pages on a single tap at the edge of a page
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureHandler:)];
tapGesture.cancelsTouchesInView = NO;
[self addGestureRecognizer:tapGesture];
[tapGesture release];
and my gesture handler:
- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {
const CGFloat kTapMargin = 180;
// Get the position of the point tapped in the window co-ordinate system
CGPoint tapPoint = [gestureRecognizer locationInView:nil];
// If the tap point is to the left of the page then go back a page
if (tapPoint.x > (self.frame.size.width - kTapMargin)) [self scrollRectToVisible:pageViewRightFrame animated:YES];
// If the tap point is to the right of the page then go forward a page
else if (tapPoint.x < kTapMargin) [self scrollRectToVisible:pageViewLeftFrame animated:YES];
}
All works well, except where I have a subview on the page that has buttons in it. I want to be able to ignore the tap to turn the page if the user touches a button on the subView and I can't figure out how to do this.
Cheers
Dave
The solution that worked the best for me in the end was to use the hitTest to determine if there were any buttons underneath the location of the tap gesture. If there are then just ignore the rest of the gesture code.
Seems to work well. Would like to know if there are any gotchas with what I have done.
- (void) tapGestureHandler:(UIGestureRecognizer *) gestureRecognizer {
const CGFloat kTapMargin = 180;
// Get the position of the point tapped in the window co-ordinate system
CGPoint tapPoint = [gestureRecognizer locationInView:nil];
// If there are no buttons beneath this tap then move to the next page if near the page edge
UIView *viewAtBottomOfHeirachy = [self.window hitTest:tapPoint withEvent:nil];
if (![viewAtBottomOfHeirachy isKindOfClass:[UIButton class]]) {
// If the tap point is to the left of the page then go back a page
if (tapPoint.x > (self.bounds.size.width - kTapMargin)) [self scrollRectToVisible:pageViewRightFrame animated:YES];
// If the tap point is to the right of the page then go forward a page
else if (tapPoint.x < kTapMargin) [self scrollRectToVisible:pageViewLeftFrame animated:YES];
}
}
Apple documentation shows the answer:
- (void)viewDidLoad {
[super viewDidLoad];
// Add the delegate to the tap gesture recognizer
self.tapGestureRecognizer.delegate = self;
}
// Implement the UIGestureRecognizerDelegate method
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch {
// Determine if the touch is inside the custom subview
if ([touch view] == self.customSubview){
// If it is, prevent all of the delegate's gesture recognizers
// from receiving the touch
return NO;
}
return YES;
}
Of course in this case customSubview would be subview on the page that has buttons in it (or even the buttons on it)
Swift 3
Set UITapGestureRecognizer
let tap = UITapGestureRecognizer(target: self, action: #selector(Class.didTap))
tap.delegate = self
UITapGestureRecognizer delegate method:
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
return touch.view != buttonThatShouldCancelTapGesture
}
You can subclass UIView and overwrite the -touchesBegan selector, or you can play with the opaque property of the subviews to make them "invisible" to the touches (if view.opaque = NO, the view ignores touch events).

UIGestureRecognizer ending

I would like to handle the rotation gesture in my iPhone app and rotate an imageView during this. At the end of the gesture I would like to rotate to a fix position the imageView.
So ie. if I rotate the imageView from 0 radian to M_PI/2 radians, but somewhere on halfway I end with the gesture. After the end I would like to test the angle and if it close to M_PI/2 then set it to M_PI/2 otherwise to 0.
Here's my code how I tried to do this:
I create and add the recognizer to my view.
UIGestureRecognizer *recognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(gestureRecognized:)];
recognizer.delegate = self;
[self addGestureRecognizer:recognizer];
[recognizer release];
Delegate methods:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (_imageView) {
return YES;
}
return NO;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Gesture recognized method:
- (void)gestureRecognized:(UIRotationGestureRecognizer *)recognizer {
_imageView.transform = CGAffineTransformMakeRotation(recognizer.rotation);
}
These methods are working, but here's the method how I tried to get the end of the gesture. This is not working:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"gesture end");
}
Also with the transform I have a little problem. Sometimes it is going back to the 0 radian.
Any suggestion is welcome. Thanks!
I've found the answer on an other forum. I hope this will help somebody else too.
Answer:
You can detect the end of the gesture by checking the UIRotationGestureRecognizer's state in your action method. If [gestureRecognizer state] == UIGestureRecognizerStateEnded then it's done. If something had instead caused it to be cancelled (for instance, a phone call coming in) then you'd see it end in UIGestureRecognizerStateCancelled instead.
If you want to apply the recognizer's rotation directly to your view rather than treat it as a delta from the previous location you can set the recognizer's rotation the its state is UIGestureRecognizerStateBegan, and then it will calculate offsets from that value and you can apply them directly. This just requires that you remember the rotation you last ended at, and then you can do something like [gestureRecognizer setRotation:lastAppliedRotation] when the recognizer's state is UIGestureRecognizerStateBegan.
If the gestureRecognizer recognizes the gesture, by default touchesEnded won't be called (touchesCancelled will be called instead. touchesEnded would only be called if the recognizer doesn't recognize the gesture). Set gestureRecognizer.delaysTouchesEnded to NO, and it should work.
Just in case this happens to you as well and it's the reason you're reading that question :
"ended" and "recognized" are the same value ( 3 ). So this code (in swift) won't work:
if (gesture.state == .recognized || gesture.state == .changed) {
}
else if (gesture.state == .ended) {
//do something else
//=> never called
}