I have added Long Tap gesture on UIWebView. But I want UIWebView to process a standard Tap event before my Long Tap will be recognized. (Two gestures should be processed on Long Tap - a simple Tap and my Long Tap). How to do this?
I think it's required to send Tap event to UIWebView on TouchBegin. Is it correct?
The correct code:
- (void)viewDidLoad {
UILongPressGestureRecognizer* gesture = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)] autorelease];
gesture.delegate = self;
[myWebView addGestureRecognizer:gesture];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Please refer this section UIGestureRecognizerDelegate
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIGestureRecognizerDelegate_Protocol/Reference/Reference.html
you found this is called when 2 gesture simultaneous work.
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:
Related
We're building an app that takes advantage of the new UICollectionView in iOS 6. However, we need to implement a long-press behavior such that even if the user then moves their finger after, we want it ignored.
i.e.
User touches the screen than instantly moves -> Swipe
User touches the screen, pauses, then moves -> Ignore swipe and wait for the release.
Basically, we only want to allow the built-in swipe gesture to be enabled if our gesture recognizer fails. However, we're not sure how to supersede the built-in swipe gesture recognizers with that 'Other recognizer must fail first' logic.
We're not sure if we're allowed to simply walk the chain trying to find the UIScrollView and interrogate that as we don't know if that violates Apple's guidelines, and if I remember correctly, they actually warn against messing with their recognizers anyway.
So how can we create tap-to-hold recognizers that supersede the built in ones?
There's an example on page 36 of the UICollectionView programming guide:
UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTapGesture:)];
NSArray* recognizers = [self.collectionView gestureRecognizers];
// Make the default gesture recognizer wait until the custom one fails.
for (UIGestureRecognizer* aRecognizer in recognizers) {
if ([aRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
[aRecognizer requireGestureRecognizerToFail:tapGesture];
}
}
// Now add the gesture recognizer to the collection view.
tapGesture.numberOfTapsRequired = 2;
[self.collectionView addGestureRecognizer:tapGesture];
Original answer
Have a look at UITapGestureRecognizerDelegate, which can be used to allow two gesture recognizers to process touches at once:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
For more info, see a tutorial such as this:
http://www.raywenderlich.com/6567/uigesturerecognizer-tutorial-in-ios-5-pinches-pans-and-more
Before your new UILongPressGestureRecognizer transnitions from the possible state, he will ask its delegate gestureRecognizerShouldBegin:. You can use that delegate method to cancel (force to failed state) any other gesture recogniser attached to the same view.
You do this by implementing the following as a delegate for your new UILongPressGestureRecognizer:
#implementation DragPictogramGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
for (UIGestureRecognizer *gr in gestureRecognizer.view.gestureRecognizers) {
if ([gr isKindOfClass:[UILongPressGestureRecognizer class]] == NO) {
gr.enabled = NO;
gr.enabled = YES;
}
}
return YES;
}
#end
Further more, in order to allow the user to use your new UILongPressGestureRecognizer with one finger, and use another finger to scroll the UICollectionView at the same time, you can implement the following delegate in the same class.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Im slightly confused by a method in the UIGestureRecognizerDelegate protocol. When I implement the delegate method below, I don't seem to ever get my UITapGestureRecognizers sent to this method with their state as UIGestureRecognizerStateRecognized. They are always in the state UIGestureRecognizerStatePossible. Is this right?
Below is the test code I used to setup my Tap Gesture and my test implementation of the delegate method:
UITapGestureRecognizer *singelTap = [[UITapGestureRecognizer alloc] initWithTarget:nil action:nil];
singelTap.numberOfTapsRequired = 1;
singelTap.delegate = self;
[self.view addGestureRecognizer:singelTap];
.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
int i = 0;
if(gestureRecognizer.state == UIGestureRecognizerStateBegan){
i=1;
}
if(gestureRecognizer.state == ..... //testing for all possible states...
return YES;
}
This is correct. When you implement the
(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
method, you get an opportunity to decide if the UIGestureRecognizer should receive the touch. That means that it has not received the touch yet. Because the UIGestureRecognizer in question has not received anything to do with that particular touch yet, it hasn't been able to determine if it Recognized it or not; thus it remains in the state UIGestureRecognizerStatePossible during this method.
If you return YES from the method, the touch will be sent to the UIGestureRecognizer.
Only then will the UIGestureRecognizer handle the touch.
The UIGestureRecognizerDelegate protocol is only to fine-tune the gesture recognizer's behavior. The actual recognition of events is done by setting a target and a selector:
UITapGestureRecognizer *gr = [[[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleTap:)] autorelease];
// add gr to a view
-(void)handleTap:(UITapGestureRecognizer*)tg
{
if ( tg.state != UIGestureRecognizerStateRecognized ) return;
NSLog(#"tap recognized");
}
In most cases, you can safely ignore the UIGestureRecognizerDelegate protocol.
Found this in the documents
This method is called before touchesBegan:withEvent: is called on the gesture recognizer for a new touch.
So I guess the touch can only ever be in the 'possible' state.
In one of my application, I don't want to show any video controllers. But I need to get the touch on the media player view. I need to do some other action on touch on the movie player. How can I implement that. Please help
Thanks in advance.
You can always attach a UITapGestureRecognizer to the view and handle the taps.
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTap:)];
[moviePlayer.view addGestureRecognizer:tap];
[tap release];
And handle the tap in handleTap:
- (void)handleTap:(UITapGestureRecognizer *)gesture {
// Do some other action as intended.
}
Of course this works only on iOS 3.2 and later.
You can also use this delegate method of UIGestureRecognizer.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
I've got an app that displays a page of text with the ability to tap a button or swipe in a view to advance or retreat through various pages. The container view has two UISwipeGestureRecognizers attached, for swipe left and swipe right. No trouble with these gestures. But now I'm trying to add UITapGestureRecognizer to another view, providing an ability similar to iBooks or the Kindle app, tap the left to go back, the right to go forward. Nothing I do can get the gesture to fire. No hint that it is ever being triggered, even if I put the gesture on my topmost view and disable other gestures.
The view controller implements UIGestureRecognizerDelegate, though I've not needed to implement delegate methods. I did try implementing shouldReceiveTouch: without success.
Here's a snippet of code where I create and attach the gesture recognizer:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureTurnPage:)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];
Try this on the view you're adding the gesture recognizers:
view.userInteractionEnabled = YES;
You mention that you've tried this, but just in case go through it again.
Try using the delegate with <UIGestureRecognizerDelegate> in the header and then setting the delegate:
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureTurnPage:)];
[self.view addGestureRecognizer:recognizer];
recognizer.delegate = self;
[recognizer release];
Then implement this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
return YES;
}
Then use a debugger or toss an NSLog into the above method and also tapGestureTurnPage: to see if these methods are being called.
Add this where you initialize the gesture:
recognizer.delegate = self;
and add this in the "self" class:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
This allows me to have gestures recognized on the UIWebView, and the UIWebView will still respond to the taps. (which i wanted - you may not)
Hello I have an opengl view and on that I have a tab bar. I'm using a tap recognizer to tap different 3d objects on screen. In the tab bar I have a button but it doesn't work because the tap recognizer catches these taps too. How do I stop this? I've already tried this:
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([touch.view isKindOfClass:[UIBarButtonItem class]]) return FALSE;
return TRUE;
}
I think I am somehow comparing wrong classess because when I debug it returns TRUE always.
Or you can just do [singleTap setCancelsTouchesInView:NO]. Example:
UITapGestureRecognizer *singleTap = [
[UITapGestureRecognizer alloc]
initWithTarget: self
action: #selector(yourSelector:)
];
[singleTap setCancelsTouchesInView:NO];
[[self view] addGestureRecognizer: singleTap];
if ([touch.view.superview isKindOfClass:[UIToolbar class]]) return FALSE;
This is how I got it to work. The superview is a UIToolbar, probably UIBarButtonIttem is a view after all.