Dismiss modal view form sheet controller on outside tap Dismiss modal view form sheet controller on outside tap xcode xcode

Dismiss modal view form sheet controller on outside tap


I know this is an old question but this IS possible, despite of what the "right" answer says. Since this was the first result when I was looking for this I decided to elaborate:

This is how you do it:

You need to add a property to the View Controller from where you want to present modally, in my case "tapBehindGesture".

then in viewDidAppear

if(!tapBehindGesture) {        tapBehindGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapBehindDetected:)];        [tapBehindGesture setNumberOfTapsRequired:1];        [tapBehindGesture setCancelsTouchesInView:NO]; //So the user can still interact with controls in the modal view    }[self.view.window addGestureRecognizer:tapBehindGesture];

And Here is the implementation for tapBehindDetected

- (void)tapBehindDetected:(UITapGestureRecognizer *)sender{    if (sender.state == UIGestureRecognizerStateEnded)    {        //(edited) not working for ios8 above         //CGPoint location = [sender locationInView:nil]; //Passing nil gives us coordinates in the window        CGPoint location = [sender locationInView: self.presentingViewController.view];        //Convert tap location into the local view's coordinate system. If outside, dismiss the view.        if (![self.presentedViewController.view pointInside:[self.presentedViewController.view convertPoint:location fromView:self.view.window] withEvent:nil])        {               if(self.presentedViewController) {                [self dismissViewControllerAnimated:YES completion:nil];            }        }    }}

Just remember to remove tapBehindGesture from view.window on viewWillDisappear to avoid triggering handleTapBehind in an unallocated object.


I solved iOS 8 issue by adding delegate to gesture recognizer

[taprecognizer setDelegate:self];

with these responses

#pragma mark - UIGestureRecognizer Delegate- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {    return YES;}- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {    return YES;}- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {    return YES;}

that works for me with iOS 8 GM


As far as I can tell none of the answer seem to be working right away in every condition.

My solution (either inherit from it or paste it in):

@interface MyViewController () <UIGestureRecognizerDelegate>@property (strong, nonatomic) UITapGestureRecognizer *tapOutsideRecognizer;@end-(void)viewDidAppear:(BOOL)animated{    [super viewDidAppear:animated];    if (!self.tapOutsideRecognizer) {        self.tapOutsideRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)];        self.tapOutsideRecognizer.numberOfTapsRequired = 1;        self.tapOutsideRecognizer.cancelsTouchesInView = NO;        self.tapOutsideRecognizer.delegate = self;        [self.view.window addGestureRecognizer:self.tapOutsideRecognizer];    }}-(void)viewWillDisappear:(BOOL)animated{    [super viewWillDisappear:animated];    // to avoid nasty crashes    if (self.tapOutsideRecognizer) {        [self.view.window removeGestureRecognizer:self.tapOutsideRecognizer];        self.tapOutsideRecognizer = nil;    }}#pragma mark - Actions - (IBAction)close:(id)sender{    [self dismissViewControllerAnimated:YES completion:nil];}- (void)handleTapBehind:(UITapGestureRecognizer *)sender{    if (sender.state == UIGestureRecognizerStateEnded)    {        CGPoint location = [sender locationInView:nil]; //Passing nil gives us coordinates in the window        //Then we convert the tap's location into the local view's coordinate system, and test to see if it's in or outside. If outside, dismiss the view.        if (![self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil])        {            // Remove the recognizer first so it's view.window is valid.            [self.view.window removeGestureRecognizer:sender];            [self close:sender];        }    }}#pragma mark - Gesture Recognizer// because of iOS8- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{    return YES;}