Reject the modular view form controller on the external crane

I present the modal view controller as a form sheet and reject it when the cancel button that is an element of the panel button is pressed. I need to fire him when I go beyond this point of view. Please help me with the link. Note: my modal view controller is represented by a navigation controller.

@cli_hlt, @Bill Brasky thanks for your reply. I need to fire him when the tap happens outside the modal view, which is a sheet of form. I embed 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 location into the local view coordinate system, and test to see if it 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]; } } } 
+32
objective-c xcode uinavigationcontroller modalviewcontroller
Feb 01 2018-12-01T00:
source share
13 answers

Good. Therefore, I am afraid that this is not possible using the presentModalViewController: method. The whole idea of โ€‹โ€‹a "modal" viewport / window / message / etc. pp. that the user cannot do anything else but process all view windows / windows / messages / etc. pp. wants him / her to do.

Instead, you donโ€™t see a modal view controller, but rather load and display your view controller. Note that in your main controller, the form just displays, for example. with a BOOL variable, and then handle any taps that may arise. If your form is displayed, release it.

+3
Feb 01 2018-12-12T00:
source share

I know this is an old question, but it is possible despite saying the โ€œrightโ€ answer. Since this was the first result when I looked for it, I decided to clarify:

Here's how you do it:

You need to add the property to the view controller from which 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 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]; } } } } 

Remember to remove tapBehindGesture from view.window in viewWillDisappear to avoid running handleTapBehind in an unallocated object.

+71
Apr 04 '13 at 18:45
source share

I solved the iOS 8 issue by adding a delegate to the gesture recognizer

 [taprecognizer setDelegate:self]; 

with these answers

 #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; } 

which works for me with iOS 8 GM

+26
Sep 10 '14 at 15:23
source share

As far as I can tell, none of the answers seem to work right away in every condition.

My solution (either inherit it or paste it):

 @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 location into the local view coordinate system, and test to see if it 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 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; } 
+16
Mar 06 '15 at 11:38
source share

Here is my version that works for iOS 7 and iOS 8 and does not require a conditional change 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]; } } } 
+14
Sep 24 '14 at 19:35
source share

Swift 3.1 version, working both in portrait and landscape orientation - no need to replace x, y variables.

 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 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 } } 
+12
May 25 '17 at 2:46 a.m.
source share

For iOS 8, you must both implement the UIGestureRecognizer response for Martino and change the (x, y) coordinates of the place you are in in landscape orientation. Not sure if this is due to 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 location into the local view coordinate system, and test to see if it 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 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; } 
+10
Sep 11 '14 at 20:34
source share

answer @yershuachu , 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 } } 
+6
Aug 27 '15 at 11:04
source share

Based on the answer of Bart van Kuyk 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 } } 

Using:

 let vc = MyViewController() let nc = DismissableNavigationController(rootViewController: vc) nc.modalPresentationStyle = UIModalPresentationStyle.FormSheet presentViewController(nc, animated: true, completion: nil) 
+6
Jul 01 '16 at 18:33
source share

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 } 

}

+4
Dec 01 '16 at 23:17
source share

I use it in this form without any problems on either iOS 7.1 or 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; } 
+2
Apr 09 '15 at 10:19
source share

I made a navigationController that automatically rejects for iPad

https://github.com/curciosobrinho/NavAutoDismiss

This is the same code as above, running on iOS 8.

So, all loans go to people above.

I just made it more general and easy to use.

You just need to copy the BOTH files to your project

Import header file (.h)

And use your view manager (which you want to show) as 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 
0
Sep 24 '14 at 12:04 on
source share
 extension CGPoint { mutating func correctOrientation() { let screenSize = UIScreen.mainScreen().bounds switch(UIDevice.currentDevice().orientation) { case .Portrait: break case .PortraitUpsideDown: y = screenSize.height - y break case .LandscapeLeft: swap(&y, &x) y = screenSize.height - y break case .LandscapeRight: swap(&y, &x) x = screenSize.width - x break default: break } } } 
-2
Mar 28 '16 at 17:44
source share



All Articles