There are tasks that are not so simple (for me) to do on iOS. One of them is to detect a tap outside a view, for example to dismiss a modal dialog.
So, for reference, here’s how I implemented it.
First: you present a modal sheet using:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion
In your interface, declare an UITapGestureRecognizer
@property (nonatomic, strong) UITapGestureRecognizer *gesture;
Then, in your implementation:
//========================================================== - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; self.gesture.numberOfTapsRequired = 1; self.gesture.numberOfTouchesRequired = 1; self.gesture.delegate = self; [self.gesture setCancelsTouchesInView:NO]; [self.view.window addGestureRecognizer:self.gesture]; } //========================================================== - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch { CGPoint point = [touch locationInView:nil]; UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window]; CGPoint pointInSubview = [self.view convertPoint:point fromView:mainWindow]; if (!CGRectContainsPoint(self.view.frame, pointInSubview)) { [self close:self]; return NO; } return YES; // handle the touch } //========================================================== - (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer { if (gestureRecognizer.state != UIGestureRecognizerStateEnded) { return; } // Handle the tap if you want to } //========================================================== #pragma mark - Close modal - (IBAction)close:(id)sender { self.gesture.delegate = nil; [self.view.window removeGestureRecognizer:self.gesture]; [self dismissViewControllerAnimated:YES completion:^{ }]; }
That’s it. It could be easier.
Here’s a link to a Gist on GitHub, easier to read.