I have more than 20 viewcontrollers in my project and added swipe gesture in global viewcontroller class.
UISwipeGestureRecognizer *rightSwipeGesture = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(navigateToPreviousScreen:)];
rightSwipeGesture.cancelsTouchesInView = YES;
rightSwipeGesture.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:rightSwipeGesture];
And override all sub class
- (void)navigateToPreviousScreen:(UISwipeGestureRecognizer *)sender {
[self.navigationController popViewControllerAnimated:YES];}
Now i got a problem (not exactly a problem), The some of the viewcontrollers has tableviews and that swipe is not work sometimes(also got some touch sensitive issue). Is there a way to solve it. I set cancelsTouchesInView = No but seems problem occurs.
Thanks in Advance.
You should be able to fix this by implementing & returning YES in the following UIGestureRecognizerDelegate method in the parent class.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Ok, I have a WKWebView with a big textarea inside it, and when I click on it, it fires this UIWebTouchEventsGestureRecognizer and shows the keyboard.
This behavior is correct. Problem is, when scrolling or panning from any other gesture, this UIWebTouchEventsGestureRecognizer is fired and the keyboard shows.
Is there any way to prevent that?
I'm using this to get the problematic gesture recognizer:
for (UIView* subview in self.subviews) {
// here comes the tricky part, desabling
for (UIView* subScrollView in subview.subviews) {
if ([subScrollView isKindOfClass:NSClassFromString(#"WKContentView")]) {
for (UIGestureRecognizer* gesture in [subScrollView gestureRecognizers]) {
if ([gesture isKindOfClass:NSClassFromString(#"UIWebTouchEventsGestureRecognizer")]) {
gesture.delegate = self;
gesture.delaysTouchesBegan = true;
gesture.delaysTouchesEnded = true;
[gesture requireGestureRecognizerToFail:scrollGesture];
}
}
}
}
}
requireGestureRecognizerToFail: doesn't work;
-(BOOL)gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
also didn't work
The only thing that worked is returning false on this delegate method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return false;
}
But obviously, now the keyboard will never show..
Resuming, I need the webview to get focus on taps, and to ignore pans and other gestures.
Any tips?
Did you this this one ?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
Is there any such thing as a generic handler for any sort of touch event? A method that get called when any sort of interaction occurs with information about the touch event passed as a parameter.
You are going to want to adhere to the UIGestureRecognizerDelegate protocol, namely the following two methods:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
Within these methods you can check the gesture recognizer object to see if it is the type of gesture you are looking for and specify whether or not the gesture should begin or receive the touch.
EDIT: To detect the end of a gesture you would have something like this:
// in viewDidLoad or in initialization of your view controller:
_panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGestureRecognizer:)];
[self addGestureRecognizer:_panGestureRecognizer];
[_panGestureRecognizer setDelegate:self];
- (void)handlePanGestureRecognizer:(UIPanGestureRecognizer *)gesture {
UIGestureRecognizerState state = [gesture state];
if (state == UIGestureRecognizerStateEnded) {
// gesture ended here
}
}
I'm writing a module that everytime I swipe on a view, two sub views with a half size of the view will be added. Those subviews have their own gestures (eg: pan,...). The first time I swipe, it's OK because none of subview has been created. But once the subview been created, everytime I swipe, the swipe gesture is alway pass to its subviews. :(, so I have to swipe 2 times to divide.
I want to know is there any way to block swipe passing to its subview? Thank you.
UPDATE
I used shouldRecognizeSimultaneouslyWithGestureRecognizer to make those gestures work simultaneously. But there's still have some problems. The parent view have its Swipe gesture, the subview have its Pan gesture. Since I use souldRecognizeSimultaneouslyWithGestureRecognizer, sometime when I'm panning, the swipe gesture triggers. So, you know how to disable Swipe while Pan is active in this situation?
You have to implement the UIGestureRecognizerDelegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
And add your controller as the delegate of the gesture recognizers. Then, when two gesture recognizers respond to a gesture, this method will be called and here you can implement the logic you want for your app.
In the interface declaration of the controller you have to type:
#interface testcViewController () <UIGestureRecognizerDelegate>
Then, when creating the gesture recognizer:
UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipe)];
swipe.direction = UISwipeGestureRecognizerDirectionDown;
swipe.delegate = self;
[self.view addGestureRecognizer:swipe];
And then, finally, you add this method to the controller:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
BOOL shouldInteract = NO;
//Here you decide whether or not the two recognizers whould interact.
return shouldInteract;
}
EDIT
You can also implement
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
And here, detect if you have already presented the subviews, and block any gesture you want.
To block all gesture recognizers from superviews I created a UIGestureRecognizer sub class that will do just that when attached to a view. See the following code (taken from my WEPopover project):
#import "WEBlockingGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#implementation WEBlockingGestureRecognizer
- (id)init {
return [self initWithTarget:self action:#selector(__dummyAction)];
}
- (id)initWithTarget:(id)target action:(SEL)action {
if ((self = [super initWithTarget:target action:action])) {
self.cancelsTouchesInView = NO;
}
return self;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
if (self.state == UIGestureRecognizerStatePossible) {
self.state = UIGestureRecognizerStateBegan;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateRecognized;
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer {
return [self isGestureRecognizerAllowed:preventingGestureRecognizer];
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer {
return ![self isGestureRecognizerAllowed:preventedGestureRecognizer];
}
- (BOOL)shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return ![self isGestureRecognizerAllowed:otherGestureRecognizer];
}
- (BOOL)shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return NO;
}
- (BOOL)isGestureRecognizerAllowed:(UIGestureRecognizer *)gr {
return [gr.view isDescendantOfView:self.view];
}
- (void)__dummyAction {
}
#end
If you want to block all gesture recognizers attached to parent views of some view, just do the following:
- (void)blockParentGesturesForView:(UIView *)v {
[v addGestureRecognizer:[WEBlockingGestureRecognizer new]];
}
set userinteractionEnabled to NO of your subView
subview.userinteractionEnabled=NO
if you dont want to disable userInteraction then use cancelsTouchesInView method
cancelsTouchesInView—If a gesture recognizer recognizes its gesture,
it unbinds the remaining touches of that gesture from their view (so
the window won’t deliver them). The window cancels the previously
delivered touches with a (touchesCancelled:withEvent:) message. If a
gesture recognizer doesn’t recognize its gesture, the view receives
all touches in the multi-touch sequence.
try like this,
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return NO;
}
Considering that I have a dialogView as a direct subview of my UIViewController's main view I'm attaching a gesture recognizer to the main view and do the following (setting my view controller as the gesture recognizer delegate):
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
let point = touch.location(in: view)
return !dialogView.frame.contains(point)
}
Took what I read here and made a Swift 5 that works great (for me)! I have a slide control in a view that also has a swipe recognizer for moving to another view. If the finger doesn't hit the slider's thumb, then the whole view moves.
By placing this view under the slider (expanded so its somewhat bigger), misses don't do anything.
final class BlockingView: UIView, UIGestureRecognizerDelegate {
let swipe: UISwipeGestureRecognizer = UISwipeGestureRecognizer();
init() {
super.init(frame: CGRect.zero)
swipe.direction = [.left, .right]
self.addGestureRecognizer(swipe)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
#objc override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { return false }
}
Hope this saves someone the trouble!
I have an app with a MKMapView and code that is called each time the map changes locations (in regionDidChangeAnimated). When the app initially loads, regionDidChangeAnimated is called on pans (swipes), pinches, taps and buttons that explicitly update the map coordinates. After loading other views and coming back to the map the regionDidChangeAnimated is only called for taps and the buttons that explicitly update the map. Panning the map and pinches no longer call regionDidChangeAnimated.
I have looked at this stackoverflow post which did not solve this issue. The forum posts on devforums and iphonedevsdk also did not work. Does anyone know what causes this issue? I am not adding any subviews to MKMapView.
I did not want to initially do it this way, but it appears to work with no problems so far (taken from devforums post in question):
Add the UIGestureRecognizerDelegate to your header.
Now add a check for the version number... If we're on iOS 4 we can do this:
if (NSFoundationVersionNumber >= 678.58){
UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchGestureCaptured:)];
pinch.delegate = self;
[mapView addGestureRecognizer:pinch];
[pinch release];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panGestureCaptured:)];
pan.delegate = self;
[mapView addGestureRecognizer:pan];
[pan release];
}
Add the delegate methods to handle the gestures:
#pragma mark -
#pragma mark Gesture Recognizers
- (void)pinchGestureCaptured:(UIPinchGestureRecognizer*)gesture{
if(UIGestureRecognizerStateEnded == gesture.state){
///////////////////[self doWhatYouWouldDoInRegionDidChangeAnimated];
}
}
- (void)panGestureCaptured:(UIPanGestureRecognizer*)gesture{
if(UIGestureRecognizerStateEnded == gesture.state){
///////////////////[self doWhatYouWouldDoInRegionDidChangeAnimated];
}
}
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
return YES;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch: (UITouch *)touch{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}