56 votes

UIPageViewController Reconnaisseurs de gestes

J'ai un UIPageViewController chargé avec mon Viewcontroller.

Les contrôleurs de vue ont des boutons qui sont surchargés par les reconnaissances de gestes des PageViewControllers.

Par exemple, j'ai un bouton sur le côté droit du viewcontroller et lorsque vous appuyez sur le bouton, le PageViewController prend le relais et change la page.

Comment faire en sorte que le bouton reçoive le toucher et annule la reconnaissance des gestes dans le PageViewController ?

Je pense que le PageViewController fait de mon ViewController une sous-vue de sa vue.

Je sais que je pourrais désactiver tous les gestes, mais ce n'est pas l'effet que je recherche.

Je voudrais préférez de ne pas sous-classer le PageViewController car apple dit que cette classe n'est pas destinée à être sous-classée.

0 votes

J'ai également travaillé sur une application qui utilise PageViewController ... et je cherche un moyen de changer les pages de manière programmatique ... pouvez-vous m'aider un peu sur ce point ?

2 votes

Sûr. Pour changer une page de manière programmatique, vous devez faire ceci : NSArray *viewControllers = [NSArray arrayWithObject:pageIWantToTurnTo]; puis [pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

0 votes

Y a-t-il un exemple où l'achèvement n'est pas NULL ?

56voto

Pat McG Points 568

Voici une autre solution, qui peut être ajoutée dans l'onglet viewDidLoad juste après le modèle self.view.gestureRecognizers = self.pageViewController.gestureRecognizers à partir du modèle Xcode. Il évite de toucher aux entrailles du système de reconnaissance des gestes ou de s'occuper de ses délégués. Il supprime simplement la reconnaissance des gestes de tapotement des vues, ne laissant que la reconnaissance de glissement.

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

// Find the tap gesture recognizer so we can remove it!
UIGestureRecognizer* tapRecognizer = nil;    
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
    if ( [recognizer isKindOfClass:[UITapGestureRecognizer class]] ) {
        tapRecognizer = recognizer;
        break;
    }
}

if ( tapRecognizer ) {
    [self.view removeGestureRecognizer:tapRecognizer];
    [self.pageViewController.view removeGestureRecognizer:tapRecognizer];
}

Maintenant, pour passer d'une page à l'autre, vous devez glisser. Les tapotements ne fonctionnent plus que sur les commandes situées en haut de la page (ce que je voulais).

2 votes

J'aime bien que cette méthode ne s'embarrasse pas de la définition du délégué de la reconnaissance des gestes.

0 votes

Une bien meilleure solution. Cependant, j'ai fini par activer et désactiver tapRecognizer, car j'avais à nouveau besoin d'activer le geste du toucher après qu'une vue secondaire ait été rejetée.

0 votes

Très simple. Je le préfère. Merci.

50voto

jramer Points 441

Vous pouvez passer outre

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
 shouldReceiveTouch:(UITouch *)touch

pour mieux contrôler quand le PageViewController doit recevoir le toucher ou non. Consultez la section "Empêcher les reconnaisseurs de gestes d'analyser les touchers" dans le document intitulé Dev API Reconnaisseurs de gestes

Ma solution ressemble à ceci dans le RootViewController pour le UIPageViewController :

Dans viewDidLoad :

//EDITED Need to take care of all gestureRecogizers. Got a bug when only setting the delegate for Tap
for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

L'annulation :

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    //Touch gestures below top bar should not make the page turn.
    //EDITED Check for only Tap here instead.
    if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        CGPoint touchPoint = [touch locationInView:self.view];
        if (touchPoint.y > 40) {
            return NO;
        }
        else if (touchPoint.x > 50 && touchPoint.x < 430) {//Let the buttons in the middle of the top bar receive the touch
            return NO;
        }
    }
    return YES;
}

Et n'oubliez pas de définir le RootViewController comme UIGestureRecognizerDelegate.

(Pour info, je suis seulement en mode paysage.)

EDIT - Le code ci-dessus a été traduit en Swift 2 :

Dans viewDidLoad :

for gr in self.view.gestureRecognizers! {
    gr.delegate = self
}

Faire en sorte que le contrôleur de la vue de la page hérite UIGestureRecognizerDelegate puis ajoutez :

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if let _ = gestureRecognizer as? UITapGestureRecognizer {
        let touchPoint = touch .locationInView(self.view)
        if (touchPoint.y > 40 ){
            return false
        }else{
            return true
        }
    }
    return true
}

0 votes

Merci, cela a résolu mon problème. Dans mon cas, je voulais que le geste de tapotement soit sous mon contrôle total, indépendamment de la position du toucher, donc le code était encore plus simple : il vérifie simplement si le gestureRecognizer est de la classe UITapGestureRecognizer.

13 votes

Il semble y avoir un problème avec cette solution, du moins dans mon cas. Une fois que j'ai changé le délégué de la reconnaissance des gestes, j'ai commencé à obtenir NSInvalidArgumentException à chaque fois viewControllerBeforeViewController o viewControllerAfterViewController retourne un résultat nul (indiqué sur la dernière page). Raison de l'exception : The number of view controllers provided (0) doesn't match the number required (2) for the requested transition .

0 votes

Les exceptions NSInvalidArgumentExceptions que vous obtenez semblent se produire uniquement sur iOS 6 lors de l'utilisation de la transition pagecurl. Elles peuvent être évitées en renvoyant [self viewControllerAtIndex:0] au lieu de nil (pour viewControllerBeforeViewController) et [self viewControllerAtIndex:maxpages] au lieu de nil (pour viewControllerAfterViewController) - un effet secondaire malheureux est l'animation supplémentaire de page curl.

4voto

Phillip Points 31

J'ai eu le même problème. L'échantillon et la documentation font cela dans loadView ou viewDidLoad :

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

Cela remplace les reconnaissances de gestes des vues UIViewControllers par les gestureRecognizers de l'UIPageViewController. Maintenant, lorsqu'un toucher se produit, il est d'abord envoyé à travers les reconnaisseurs de gestes du pageViewController - s'il ne correspond pas, il est envoyé aux sous-vues.

Il suffit de décommenter cette ligne, et tout fonctionne comme prévu.

Phillip

3voto

noRema Points 378

La configuration du délégué gestureRecognizers à un viewController comme ci-dessous ne fonctionne plus sur ios6

for (UIGestureRecognizer *gR in self.view.gestureRecognizers) {
    gR.delegate = self;
}

Dans ios6, le fait de définir le délégué gestureRecognizers de votre pageViewController à un viewController provoque un plantage.

0voto

isaac Points 3632

Si vous utilisez un bouton que vous avez sous-classé, vous pouvez remplacer les touchesBegan, touchesMoved et touchesEnded, en invoquant votre propre programme de mise en page, le cas échéant, mais sans appeler super et en faisant remonter les touches dans la chaîne de notification.

0 votes

Sataym, suggérez-vous qu'il est impossible de placer des boutons ou des éléments interactifs dans un UIPageViewController ? Et qu'Apple a simplement oublié de le mentionner dans toute la documentation de UIPageViewController ?

0 votes

Aucun regard sur la réponse de Philips. Tant que nous n'avons pas commenté cette ligne de code, aucun des contrôles ne recevra d'événements tactiles, sauf s'il s'agit de la première vue. Après avoir commenté cette ligne de code, n'importe quel bouton personnalisé, étiquette, UIButton ou autre recevra des événements tactiles.

0 votes

J'ai couru là-dedans aussi. J'ai un bouton en bas au milieu de la page. Cela semble fonctionner, mais pas s'il est placé à gauche ou à droite.

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