Dismiss modal view form sheet controller on outside tap
Asked Answered
L

14

34

I am presenting a modal view controller as a form sheet and dismissing it when the cancel button, which is a bar button item, is clicked. I need to dismiss it when I tap on outside of that view. Please help me with a reference. Note: my modal view controller is presented with a navigation controller.

@cli_hlt, @Bill Brasky thanks for your answer. I need to dismiss it when tap occurs outside of the modal view which is a form sheet. I am pasting my code below.

-(void)gridView:(AQGridView *)gridView didSelectItemAtIndex:(NSUInteger)index  
{        
    if(adminMode) 
    {
        CHEditEmployeeViewController *editVC = [[CHEditEmployeeViewController alloc] initWithNibName:@"CHEditEmployeeViewController" bundle:nil];
        editVC.delegate = self;
        editVC.pickedEmployee = employee;
        editVC.edit = TRUE;
        editVC.delegate = self;
        UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:editVC];
        navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
        [self presentModalViewController:navigationController animated:YES];

        return;
    }   //the above code is from the view controller which presents the modal     view. Please look at the below code too which is from my modal view controller. Please guide me in a proper way.   -(void)tapGestureRecognizer {

    UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)];
    [recognizer setNumberOfTapsRequired:1];
    recognizer.cancelsTouchesInView = NO; //So the user can still interact with controls in the modal view
    [self.view addGestureRecognizer:recognizer];

}

- (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]) 
        {
            [self dismissModalViewControllerAnimated:YES];
            [self.view.window removeGestureRecognizer:sender];
        }

    }
}
Landscapist answered 1/2, 2012 at 20:7 Comment(0)
A
2

Ah ok. So I'm afraid thats not quite possible using the presentModalViewController: method. The whole idea of a "modal" view/window/message box/etc. pp. is that the user cannot do anything else than processing whatever the view/window/message box/etc. pp. wants him/her to do.

What you want to do instead is not present a modal view controller, but rather load and show your form view controller the regular way. Note in your master controller that the form is just showing e.g. with a BOOL variable and then handle there any taps that might occur. If your form is showing, dismiss it.

Adenitis answered 1/2, 2012 at 20:17 Comment(4)
This will also dismiss the modal if you tap on anything inside the modal view as well that isn't wired up. (blank space, etc.)Omalley
I thought his/her intent was to dismiss the modal when tapping outside of the form elements - not just the cancel button?Adenitis
Possibly. Just thought it was worth mentioning in case that doesn't give the expected results. The question seemed like they wanted it to dismiss when tapping outside the form sheet view, so wanted to make things clear.Omalley
I have edited my question, Please have a look at them.Thanks.Landscapist
O
73

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.

Overstock answered 4/4, 2013 at 18:45 Comment(9)
Works very well (iOS7). Other people using this code should take note of self.presentedViewController.view. If implementing the gesture inside the modal view controller, you should just use self.view instead.Cytochemistry
Does anyone know how to fix this for iOS8? or is there perhaps a better solution?Lederer
Kevin, what do you mean by "fix"in iOS8? What problem are you getting?Overstock
@Overstock I also have issues with iOS8 as Kevin. And I know we shouldn't be discussing beta versions here so follow this link: devforums.apple.com/thread/243768Rhinarium
adding the UIGestureRecognizerDelegate from below does work, but it seems convertPoint:fromView: returns a different value in iOS8 than iOS7, so the tap location is inaccurate.Shuttlecock
on second look, it might be rather that locationInView: has a different return in iOS 8Shuttlecock
Got this all working right in iOS 8. In addition to adding the UIGestureRecognizer, swap location if it's in landscape orientation.Shuttlecock
I changed the location by follow code: CGPoint location = [tapSender locationInView: self.presentingViewController.view];Godroon
@orafaelreis, indeed this is the only solution that worked for me. thanks a lot! This answer seems to be broken, it needs replacing with your answer.Kathyrnkati
E
26

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

Elusive answered 10/9, 2014 at 15:23 Comment(2)
That worked! In particular, gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer needs to be implemented to return YESBayly
There's also a problem with coordinates in landscape orientation. See my solution here: https://mcmap.net/q/450681/-dismiss-modal-form-sheet-view-on-outside-tap-ios-8Bayly
P
19

Swift 4 version that works in both portrait and landscape - no swapping of x, y required.

class TapBehindModalViewController: UIViewController, UIGestureRecognizerDelegate {
private var tapOutsideRecognizer: UITapGestureRecognizer!

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if (self.tapOutsideRecognizer == nil) {
        self.tapOutsideRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTapBehind))
        self.tapOutsideRecognizer.numberOfTapsRequired = 1
        self.tapOutsideRecognizer.cancelsTouchesInView = false
        self.tapOutsideRecognizer.delegate = self
        self.view.window?.addGestureRecognizer(self.tapOutsideRecognizer)
    }
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if(self.tapOutsideRecognizer != nil) {
        self.view.window?.removeGestureRecognizer(self.tapOutsideRecognizer)
        self.tapOutsideRecognizer = nil
    }
}

func close(sender: AnyObject) {
    self.dismiss(animated: true, completion: nil)
}

// MARK: - Gesture methods to dismiss this with tap outside
@objc func handleTapBehind(sender: UITapGestureRecognizer) {
    if (sender.state == UIGestureRecognizerState.ended) {
        let location: CGPoint = sender.location(in: self.view)

        if (!self.view.point(inside: location, with: nil)) {
            self.view.window?.removeGestureRecognizer(sender)
            self.close(sender: sender)
        }
    }
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

}

Pomiferous answered 25/5, 2017 at 2:46 Comment(2)
Minor improvement for correctly handling view controllers that are presented from the TapBehindModalViewController: func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return self.presentedViewController == nil }Outport
Hi! For me handleTapBehind did not get called at all.Illinium
C
16

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;
}
Caning answered 6/3, 2015 at 11:38 Comment(2)
Thanks for this answer, I translated it in Swift, see belowFarland
Why do you remove the gesture recognizer in the tapBehind method? Wouldn't that happen in viewWillDisappear anyway, following the dismiss?Kazan
C
14

Here is my version that works for iOS 7 and iOS 8 and does not require conditional swapping of coordinates:

- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
    if (sender.state == UIGestureRecognizerStateEnded)
    {
        CGPoint location = [sender locationInView:self.view];

        if (![self.view pointInside:location withEvent:nil]) {
            [self.view.window removeGestureRecognizer:self.recognizer];
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    }
}
Certification answered 24/9, 2014 at 19:35 Comment(3)
This answer is really simple, it makes sense, and works as advertised. I'm sort of confused as to why the other answers are trying to do something much more complicated.Xeric
Great answer. Works like a charm in iOS8.Folio
It didn't work for landscape orientation (iOS8 - iPad).Atonic
S
10

For iOS 8, you must both implement the UIGestureRecognizer per Martino's answer, and swap the (x,y) coordinates of the tapped location when in landscape orientation. Not sure if this is due to an iOS 8 bug.

- (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    // add gesture recognizer to window

    UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapBehind:)];
    [recognizer setNumberOfTapsRequired:1];
    recognizer.cancelsTouchesInView = NO; //So the user can still interact with controls in the modal view
    [self.view.window addGestureRecognizer:recognizer];
    recognizer.delegate = self;
}

- (void)handleTapBehind:(UITapGestureRecognizer *)sender
{
    if (sender.state == UIGestureRecognizerStateEnded) {

        // passing nil gives us coordinates in the window
        CGPoint location = [sender locationInView:nil];

        // swap (x,y) on iOS 8 in landscape
        if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
            if (UIInterfaceOrientationIsLandscape([UIApplication sharedApplication].statusBarOrientation)) {
                location = CGPointMake(location.y, location.x);
            }
        }

        // 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 dismissViewControllerAnimated:YES completion:nil];
        }
    }
}


#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;
}
Shuttlecock answered 11/9, 2014 at 20:34 Comment(3)
On the iOS 8 GM, I don't need to do this, so it must have been a bug that was fixed.Ectoderm
It hasn't been fixed, I needed to apply this fix on iOS 8.0.2Rover
@Shuttlecock again in landscape mode on iPad your answer detects taps inside the modal view but not taps outside.Madrepore
F
6

@yershuachu's answer, in Swift 2:

class ModalParentViewController: UIViewController, UIGestureRecognizerDelegate {

    private var tapOutsideRecognizer: UITapGestureRecognizer!

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        if(self.tapOutsideRecognizer == nil) {
            self.tapOutsideRecognizer = UITapGestureRecognizer(target: self, action: "handleTapBehind:")
            self.tapOutsideRecognizer.numberOfTapsRequired = 1
            self.tapOutsideRecognizer.cancelsTouchesInView = false
            self.tapOutsideRecognizer.delegate = self
            self.view.window?.addGestureRecognizer(self.tapOutsideRecognizer)
        }
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        if(self.tapOutsideRecognizer != nil) {
            self.view.window?.removeGestureRecognizer(self.tapOutsideRecognizer)
            self.tapOutsideRecognizer = nil
        }
    }

    func close(sender: AnyObject) {
        self.dismissViewControllerAnimated(true, completion: nil)
    }

    func handleTapBehind(sender: UITapGestureRecognizer) {
        if (sender.state == UIGestureRecognizerState.Ended) {
            let location: CGPoint = sender.locationInView(nil)

            if (!self.view.pointInside(self.view.convertPoint(location, fromView: self.view.window), withEvent: nil)) {
                self.view.window?.removeGestureRecognizer(sender)
                self.close(sender)
            }
        }
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }

}
Farland answered 27/8, 2015 at 11:4 Comment(2)
Seems no longer to be working in iOS 9. self.view.window? is nil in a modally presented view controllerFabricate
I just tested this code works great in Xcode 7. Thank you!Express
E
6

Based on Bart van Kuik's answer and NavAutoDismiss and other great snippets here.

class DismissableNavigationController: UINavigationController, UIGestureRecognizerDelegate {
    private var tapOutsideRecognizer: UITapGestureRecognizer!

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)

        if tapOutsideRecognizer == nil {
            tapOutsideRecognizer = UITapGestureRecognizer(target: self, action: #selector(DismissableNavigationController.handleTapBehind))
            tapOutsideRecognizer.numberOfTapsRequired = 1
            tapOutsideRecognizer.cancelsTouchesInView = false
            tapOutsideRecognizer.delegate = self
            view.window?.addGestureRecognizer(tapOutsideRecognizer)
        }
    }

    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)

        if tapOutsideRecognizer != nil {
            view.window?.removeGestureRecognizer(tapOutsideRecognizer)
            tapOutsideRecognizer = nil
        }
    }

    func close(sender: AnyObject) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    func handleTapBehind(sender: UITapGestureRecognizer) {
        if sender.state == UIGestureRecognizerState.Ended {
            var location: CGPoint = sender.locationInView(nil)

            if UIInterfaceOrientationIsLandscape(UIApplication.sharedApplication().statusBarOrientation) {
                location = CGPoint(x: location.y, y: location.x)
            }

            if !view.pointInside(view.convertPoint(location, fromView: view.window), withEvent: nil) {
                view.window?.removeGestureRecognizer(sender)
                close(sender)
            }
        }
    }

    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

Usage:

let vc = MyViewController()
let nc = DismissableNavigationController(rootViewController: vc)
nc.modalPresentationStyle = UIModalPresentationStyle.FormSheet
presentViewController(nc, animated: true, completion: nil)
Endomorphic answered 1/7, 2016 at 18:33 Comment(0)
I
4

Swift 3

class ModalParentViewController: UIViewController, UIGestureRecognizerDelegate {

private var tapOutsideRecognizer: UITapGestureRecognizer!

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    if(self.tapOutsideRecognizer == nil) {
        self.tapOutsideRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.handleTapBehind))
        self.tapOutsideRecognizer.numberOfTapsRequired = 1
        self.tapOutsideRecognizer.cancelsTouchesInView = false
        self.tapOutsideRecognizer.delegate = self
        appDelegate.window?.addGestureRecognizer(self.tapOutsideRecognizer)
    }
}

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

      if(self.tapOutsideRecognizer != nil) {
        appDelegate.window?.removeGestureRecognizer(self.tapOutsideRecognizer)
        self.tapOutsideRecognizer = nil
    }
}

func close(sender: AnyObject) {
    self.dismiss(animated: true, completion: nil)
}

// MARK: - Gesture methods to dismiss this with tap outside
func handleTapBehind(sender: UITapGestureRecognizer) {
    if (sender.state == UIGestureRecognizerState.ended) {
        let location: CGPoint = sender.location(in: nil)

        if (!self.view.point(inside: self.view.convert(location, from: self.view.window), with: nil)) {
            self.view.window?.removeGestureRecognizer(sender)
            self.close(sender: sender)
        }
    }
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    return true
}

}

Idyll answered 1/12, 2016 at 23:17 Comment(2)
How do you access to appdelegate with your code ? Nothing append when I click on backgroundMiosis
@BadrFilali UIApplication.shared.delegate?.window??.addGestureRecognizer(self.tapOutsideRecognizer)Soukup
A
2

Ah ok. So I'm afraid thats not quite possible using the presentModalViewController: method. The whole idea of a "modal" view/window/message box/etc. pp. is that the user cannot do anything else than processing whatever the view/window/message box/etc. pp. wants him/her to do.

What you want to do instead is not present a modal view controller, but rather load and show your form view controller the regular way. Note in your master controller that the form is just showing e.g. with a BOOL variable and then handle there any taps that might occur. If your form is showing, dismiss it.

Adenitis answered 1/2, 2012 at 20:17 Comment(4)
This will also dismiss the modal if you tap on anything inside the modal view as well that isn't wired up. (blank space, etc.)Omalley
I thought his/her intent was to dismiss the modal when tapping outside of the form elements - not just the cancel button?Adenitis
Possibly. Just thought it was worth mentioning in case that doesn't give the expected results. The question seemed like they wanted it to dismiss when tapping outside the form sheet view, so wanted to make things clear.Omalley
I have edited my question, Please have a look at them.Thanks.Landscapist
M
2

I use it in this form without any problems neither on iOS 7.1 nor iOS 8.3.

- (void)viewDidAppear:(BOOL)animated
{
     [super viewDidAppear:animated];

     [self.view.window addGestureRecognizer:self.tapBehindGesture];
}

- (void)viewWillDisappear:(BOOL)animated
{
     [super viewWillDisappear:animated];

     [self.view.window removeGestureRecognizer:self.tapBehindGesture];
}

- (UITapGestureRecognizer*)tapBehindGesture
{    
    if (_tapBehindGesture == nil)
    {
        _tapBehindGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapBehindRecognized:)];
        _tapBehindGesture.numberOfTapsRequired = 1;
        _tapBehindGesture.cancelsTouchesInView = NO;
        _tapBehindGesture.delegate = self;
    }

    return _tapBehindGesture;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return YES;
}
Mozell answered 9/4, 2015 at 10:19 Comment(0)
R
2

FYI, on iOS 13 form sheets now have a standard dismiss gesture - they go away when you touch anywhere inside the modal and swipe it down (set the new isModalInPresentation property to false if you want to prevent that).

Rajasthan answered 25/9, 2019 at 19:31 Comment(0)
U
0

I made a navigationController that auto dismiss for iPad

https://github.com/curciosobrinho/NavAutoDismiss

It is just the same code as above, working on iOS 8.

So, all the credits go to the people above.

I just did it to be more generic and easier to use.

You just need to copy BOTH files to your project

Import the header file (.h)

And use your viewcontroller (that you want to show) as the rootViewController.

How to use it:

//Import the .h file
#import "NavDismissViewController.h"

//Instanciate your view controller (the view you want to present)

YourViewController * yourVC = [YourViewController new];

//Instanciate the NavDismissViewController with your view controller as the rootViewController

NavDismissViewController *nav = [[NavDismissViewController alloc] initWithRootViewController:yourVC];

//if you want to change the navigationBar translucent behaviour

[nav.navigationBar setTranslucent:NO];

//Choose the Modal style

nav.modalPresentationStyle=UIModalPresentationFormSheet;

//present your controller

[self presentViewController:nav animated:YES completion:nil];

//Done
Urbanist answered 24/9, 2014 at 12:4 Comment(0)
E
0

Based on some of the questions and with some improvements and updates:

- (void)tapOutsideDetected:(UITapGestureRecognizer *)sender {
    if (@available(iOS 13, *)) {} else {
        UIView *aView = self.navigationController ? self.navigationController.view : self.view;
        CGPoint location = [sender locationInView: aView];
        
        if (![aView pointInside:location withEvent:nil]) {
            [self removeGestureRecognizer:sender];
            [self dismissViewControllerAnimated:YES completion:nil];
        }
    }
}

Where:

- (void) removeGestureRecognizer:(UIGestureRecognizer *) gesture {
    if (self.recognizer) {
        UIView *aView = self.recognizer.view;
        if (aView) {
            [aView removeGestureRecognizer:self.recognizer];
        }
    }
}

In this case, the UITapGestureRecognizer has been applied to the UIViewController

Epileptic answered 16/3, 2021 at 16:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.