53 votes

Iphone SDK rejetant ViewControllers modaux sur ipad en cliquant en dehors de celui-ci

Je souhaite fermer un contrôleur de vue modale FormSheetPresentation lorsque l'utilisateur appuie en dehors de la vue modale ... J'ai vu un tas d'applications le faire (eBay sur ipad par exemple), mais je ne peux pas comprendre comment, puisque les vues inférieures sont désactivées du toucher. quand les vues modales sont affichées comme ceci (le présente-t-il comme une popover peut-être?) ... Quelqu'un a-t-il des suggestions?

127voto

Danilo Campos Points 4760

J'ai un an de retard, mais c'est assez simple à faire.

Demandez à votre contrôleur de vue modale de joindre un identificateur de geste à la fenêtre de la vue:

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

Le code de manutention:

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

C'est à peu près ça. HIG soit damné, c’est un comportement utile et souvent intuitif.

11voto

Jann Points 1238

Les autres applications ne sont pas à l'aide de Modal Vues si elles permettent à la vue de l'être rejeté en cliquant à l'extérieur de l'il. UIModalPresentationFormSheets ne peut pas être rejeté de cette façon. (ni, en effet, peut-toute UIModal dans SDK3.2). Seulement l' UIPopoverController peut être rejeté en cliquant à l'extérieur de la région. Il est très possible (bien que contre l'iPad d'Apple HIG) pour le développeur de l'application pour avoir ombragée à l'arrière-plan de l'écran et affiche ensuite l' UIPopoverController , de sorte qu'il ressemble à un UIModalPresentationFormSheets (ou d'autres UIModal Vue).

[...] UIModalPresentationCurrentContext style permet une vue contrôleur adopter le style de présentation de son parent. Dans chaque modal de vue, les zones grisées afficher le contenu sous-jacent, mais ne permettent pas de robinets dans le contenu. Par conséquent, contrairement à une fenêtre pop-over, vos points de vue modal doit toujours disposer de contrôles qui permettent à l'utilisateur pour fermer la modale de vue.

Voir la iPadProgrammingGuide sur le site du développeur pour plus d'informations (Page 46 -- "Configuration du Style de Présentation Modale, les points de Vue")

11voto

Erich Points 433

Pour iOS 8, vous devez à la fois implémenter les UIGestureRecognizer et échanger les coordonnées (x, y) de l'emplacement sélectionné en mode paysage. Pas sûr que cela soit dû à un bug 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;
}
 

10voto

Keith Points 81

Le code ci-dessus fonctionne très bien, mais je changerais l'instruction if en,

     if (!([self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil] || [self.navigationController.view pointInside:[self.navigationController.view convertPoint:location fromView:self.navigationController.view.window] withEvent:nil]))

    {
        // Remove the recognizer first so it's view.window is valid.
        [self.view.window removeGestureRecognizer:sender];
        [self dismissModalViewControllerAnimated:YES];
    }
 

Cela garantit que vous pouvez toujours interagir avec la barre de navigation. Sinon, taper dessus ferait disparaître la vue modale.

8voto

Samidjo Points 905

Copier coller ce code dans votre ModalViewController:

 - (void) viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    //Code for dissmissing this viewController by clicking outside it
    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];
        }
    }
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X