2014-09-03 3 views
17

Ho cercato di respingere la vista modale foglio di modulo a rubinetto esterno su iOS 8 senza fortuna, Ho provato questo codiceCongeda modale vista foglio di modulo a iOS rubinetto esterno 8

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

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

Ma non rileva clic di vista esterna, qualche suggerimento?

+0

Dov'è il tuo codice? – Raptor

+0

Ho pubblicato un collegamento del codice che ho provato. –

+0

Pubblica i tuoi codici correlati, non i codici di altre persone. Inoltre, * non ha funzionato * NON è una descrizione del problema valida. – Raptor

risposta

35

Ci sono in realtà due problemi in iOS 8. Innanzitutto, il riconoscimento dei gesti non inizia.

Ho risolto questo con l'aggiunta del protocollo UIGestureRecognizerDelegate e l'attuazione

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer 
{ 
    return YES; 
} 

Inoltre, non dimenticare di registrare il delegato con

recognizer.delegate = self; 

Ora il sistema di riconoscimento gesto dovrebbe riconoscere i gesti e il metodo di destinazione (handleTapBehind:) verrà chiamato.

Ecco il secondo problema in iOS 8: locationInView: non sembra prendere in considerazione l'orientamento del dispositivo se nil viene passato come una vista. Invece, passa la vista radice funziona.

Ecco il mio codice di destinazione che sembra funzionare per iOS 7.1 e 8.0:

if (sender.state == UIGestureRecognizerStateEnded) { 
    UIView *rootView = self.view.window.rootViewController.view; 
    CGPoint location = [sender locationInView:rootView]; 
    if (![self.view pointInside:[self.view convertPoint:location fromView:rootView] withEvent:nil]) { 
     [self dismissViewControllerAnimated:YES completion:^{ 
      [self.view.window removeGestureRecognizer:sender]; 
     }]; 
    } 
} 
+0

Ho seguito il tuo passi, ha funzionato perfettamente per me. Tuttavia, non sono sicuro del motivo per cui è necessario aggiungere "shouldRecognizeSimultaneouslyWithGestureRecognizer:" al primo posto. Se non si restituisce "SÌ", toccare lato della vista modale non verrà riconosciuto. Ma perché ha qualcosa a che fare con "RecognizeSimultaneouslyWithGestureRecognizer"? – DavidLiu

+0

@DavidLiu è attivo un altro riconoscimento di sistema (sistema) attivo che ha la priorità. Probabilmente un bug. – chris

+2

Questa è la soluzione migliore. E viene risolto il problema delle coordinate di rotazione che hanno altre soluzioni. Perfezionare! – MiQUEL

5

In iOS 8, si può guardare utilizzando il nuovo UIPresentationController di classe. Ti offre un controllo migliore sul contenitore attorno alla presentazione del controller di visualizzazione personalizzata (consentendoti di aggiungere correttamente un tuo riconoscitore di gesti).

Ecco un link ad un semplice tutorial altrettanto bene: http://dativestudios.com/blog/2014/06/29/presentation-controllers/

quindi aggiungere la vista oscuramento tap-to-respingere:

UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; 
    [self.dimmingView addGestureRecognizer:singleFingerTap]; 


- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer { 
    [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; 
} 
+1

Immagino che il voto negativo sia dovuto al fatto che questo tutorial parla solo dell'animazione delle transizioni e non di una funzione di esclusione da tabulazione esterna. Non chiaro se la classe UIPresentationController fa qualcosa per rispondere alla domanda in questione (senza leggere i documenti). – webjprgm

+0

Poiché UIPresentationController è l'approccio giusto, ho aggiornato la risposta per includere il tocco richiesto per eliminare il codice di esempio. E il codice di esempio di Apple va benissimo piuttosto che quel post sul blog: https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/DefiningCustomPresentations.html#//apple_ref/doc/uid/TP40007457-CH25-SW1 – malhal

+0

I preferisco questo approccio da solo, dal momento che ho avuto casi in cui un foglio di modulo presenta una vista popover il cui popover può disegnare al di fuori dei limiti del foglio di modulo presentato - e il riconoscitore di gesti basato su 'view.window' ignorerà la vista se tocchi il popover ovunque al di fuori dei limiti del foglio di forma. Preferirei molto che la vista del dimming gestisse il rubinetto! –

3

Swift soluzione 3.1 che funziona sia in verticale e orizzontale.

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

Grazie, funziona perfettamente! – mojuba