Eliminare il controller del modulo del modulo di visualizzazione modale sul rubinetto esterno

Sto presentando un controller di visualizzazione modale come un foglio di modulo e chiudendolo quando si fa clic sul pulsante Annulla, che è un elemento del pulsante di barra. Devo ignorarlo quando touch fuori da quella vista. Per favore aiutami con un riferimento. Nota: il mio controller di visualizzazione modale è presentato con un controller di navigazione.

@cli_hlt, @Bill Brasky, grazie per la tua risposta. Devo ignorarlo quando si verifica il tap fuori dalla vista modale che è un foglio di modulo. Sto incollando il mio codice qui sotto.

-(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]; } } } 

Ah ok. Quindi temo che non sia del tutto ansible usare il metodo presentModalViewController :. L’intera idea di una vista “modale” / finestra / finestra di messaggio / ecc. pp. è che l’utente non può fare nient’altro che elaborare qualunque sia la vista / finestra / message box / ecc. pp. lo vuole fare.

Quello che vuoi fare invece non è un controller di visualizzazione modale, ma piuttosto caricare e mostrare il tuo controller di visualizzazione del modulo in modo regolare. Nota nel tuo controller master che il modulo sta solo mostrando, ad esempio, una variabile BOOL e quindi gestisci tutti i tocchi che potrebbero verificarsi. Se il modulo viene visualizzato, ignoralo.

So che questa è una vecchia domanda, ma questo è ansible, nonostante ciò che dice la risposta “giusta”. Poiché questo è stato il primo risultato quando stavo cercando questo ho deciso di elaborare:

Ecco come lo fai:

È necessario aggiungere una proprietà al controller di visualizzazione da cui si desidera presentare modally, nel mio caso “tapBehindGesture”.

quindi 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]; 

Ed ecco l’implementazione per 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]; } } } } 

Ricordati di rimuovere tapBehindGesture da view.window su viewWillDisappear per evitare di triggersre handleTapBehind in un object non allocato.

Ho risolto il problema con iOS 8 aggiungendo delegato al riconoscimento dei gesti

 [taprecognizer setDelegate:self]; 

con queste risposte

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

che funziona per me con iOS 8 GM

Ecco la mia versione che funziona per iOS 7 e iOS 8 e non richiede lo scambio condizionale delle coordinate:

 - (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]; } } } 

Per quanto posso dire, nessuna delle risposte sembra funzionare immediatamente in ogni condizione.

La mia soluzione (o eredita da essa o la incolli):

 @interface MyViewController ()  @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; } 

Per iOS 8, è necessario implementare UIGestureRecognizer per la risposta di Martino e scambiare le coordinate (x, y) della località toccata quando si è in orientamento orizzontale. Non sono sicuro se questo è dovuto a un bug di iOS 8.

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

Versione Swift 4 che funziona sia in verticale che in orizzontale – non è necessario lo swap di x, y.

 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 } 

}

Basato sulla risposta di Bart van Kuik e su NavAutoDismiss e altri grandi frammenti qui.

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

Uso:

 let vc = MyViewController() let nc = DismissableNavigationController(rootViewController: vc) nc.modalPresentationStyle = UIModalPresentationStyle.FormSheet presentViewController(nc, animated: true, completion: nil) 

@ risposta di 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 } } 

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 } 

}

Lo uso in questo modulo senza problemi né su iOS 7.1 né 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; } 

Ho creato un controller di navigazione che si spegne automaticamente per iPad

https://github.com/curciosobrinho/NavAutoDismiss

È lo stesso codice di sopra, funziona su iOS 8.

Quindi, tutti i crediti vanno alle persone sopra.

L’ho appena fatto per essere più generico e più facile da usare.

Hai solo bisogno di copiare ENTRAMBI i file nel tuo progetto

Importa il file di intestazione (.h)

E usa il tuo viewcontroller (che vuoi mostrare) come rootViewController.

Come usarlo:

 //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 
 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 } } }