[Résolu] viewControllerAfterViewController appelle aussi viewControllerBeforeViewController
Bonjour,
quelqu'un a-t-il une idée pourquoi la méthode viewControllerAfterViewController appelle aussi la méthode viewControllerBeforeViewController ?
J'ai fait des tests avec des println, j'ai essayé plein de trucs depuis deux jours, j'ai cherché sur le web.
Et je ne trouve rien qui explique comment contourner ce p... de bug.
Au passage, je ne sais pas quoi mettre dans le willTransitionToViewControllers
Je met une vidéo ou on voit le projet ainsi que le code et les println
Je viens de me rendre compte qu'on ne voyait pas bien le code, donc je le met ici.
// MARK: - UIPageViewControllerDataSource
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
if let controller = viewController as? ContentEtapesViewController {
println("controller.itemIndex BEFORE = \(controller.itemIndex)")
if controller.itemIndex > 0 {
pageControl.currentPage = controller.itemIndex
levelLabel.text = levels[pageControl.currentPage]
return controllers[controller.itemIndex - 1]
} else {
pageControl.currentPage = 0
levelLabel.text = levels[0]
return nil
}
}
return nil
}
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
if let controller = viewController as? ContentEtapesViewController {
println("controller.itemIndex AFTER = \(controller.itemIndex)")
if controller.itemIndex < controllers.count - 1 {
pageControl.currentPage = controller.itemIndex
levelLabel.text = levels[pageControl.currentPage]
return controllers[controller.itemIndex + 1]
} else {
pageControl.currentPage = controllers.count
levelLabel.text = levels[pageControl.numberOfPages-1]
return nil
}
}
return nil
}
// MARK: - UIPageViewControllerDelegate
func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [AnyObject]) {
}
func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [AnyObject], transitionCompleted completed: Bool) {
if !completed {
return
}
}
On remarque que :
- La première fois que l'on avance, ça fait - after - before - after -> Pas normal
- La seconde fois, ça fait - after -> Normal
- Puis quand je recule une première fois - ça ne fait pas le before - Pas normal
- Puis la seconde fois que je recule - ça fait deux fois before - Pas normal
Merci d'avance pour la solution miracle.
Réponses
Il est indiqué dans la documentation du protocole UIPageViewControllerDataSource que ces méthodes :
1/ sont parfois appelées simultanément
2/ ne sont pas systématiquement appelées à chaque changement de page
Le comportement que tu décris n'est pas contraire au comportement documenté. Il n'y a pas de bug.
Merci pour vos réponses.
Ah oui c'est vrai, j'avais vu ça dans la doc, y' a 2 mois.
Le problème est comment détourner ce mécanisme.
Parce que, j'ai besoin, sur le premier écran, de faire, lors d'un recul, un pushViewController vers un autre controller que le pageViewController.
J'avais donc rajouté un gestureRecognizer sur le premier écran du pageViewController, pour faire le push.
Et donc, au premier after, il prenait directement le push associé au before, alors qu'il ne devrait que aller au second écran du pageViewcontroller.
J'ai donc rajouté plein de contrôles au sein des deux méthodes, et je n'y suis pas parvenu.
C'est pourquoi, j'ai supprimé le gestureRecognizer, et suis reparti dans les méthodes before/after, avec des contrôles sur le numéro de l'écran.
Et donc, je tourne en rond...
Et pour ces histoire de cache, on peut le supprimer, non ?
Je pense que si le mécanisme proposé par UIPageViewController ne te convient il suffit d'écrire un autre contrôleur de vue qui fasse ce que tu veux.
Bah donc tu fais ce push dans le viewDidAppear de la page précédente dans ce cas, ça me semble la méthode la plus adaptée ça, non ?
L'exigence du client est de naviguer avec des swipes entre plusieurs pagegeViewControllers :
- Du premier écran d'un pageView vers le dernier écran du pageview suivant (car j'ai plusieurs pageViews qui s'enchainent), ou vers un autre controller.
- Et du dernier écran d'un pageView vers le premier écran du pageView suivant, ou vers un autre controller.
Rien d'illogique dans tout ça, enfin, pour moi.
Il est trop tard pour abandonner le pageView.
Je ne veux pas détourner le mécanisme. Je me suis mal exprimé, et je n'ai ni l'ambition, ni les capacité de faire une chose pareille, mais je cherche une parade à ce pb de cache.
De quelle page précédente parles-tu ?
1- Du premier écran du pageView (Le point de départ) ?
Là , je ne peux pas mettre une détection de gesture dans le didAppear
2- Dans l'autre controller hors du pageView (la destination) ?
Ben non, puisque sur cette page je n'ai pas de pb pour entrer dans le pageview, puisque je fais un push qui va dans le premier écran du pageview en allant tout simplement sur le pageview
En gros la double question est ?
Comment à partir d'un écran d'un pageView, atteindre un autre controller que le pageView ?
Et, comment, à partir d'un autre controller que le pageView, atteindre n'importe quel écran d'un pageView ?
Et le mix des deux : Comment à partir d'un écran d'un pageView, atteindre n'importe quel écran d'un autre pageView ?
C'est sportif tout ça
J'ai essayer de placer le gesture à plusieurs endroits, et ça bloque toujours.
Je suis certain qu'il y a une astuce, c'est obligé. Cela m'étonnerai que Apple interdise ce type de navigation.
J'ai même essayé en mettant des index qui s'incrémentent dans les méthode datasource, puis de procéder à des contrôle pour empêcher que le after appelle le before et inversement, et ça bloque toujours.
Merci pour votre participation.
Pourquoi tu parles de "mettre une détection de gesture dans le didAppear" ?!? Quelle drôle d'idée, je n'ai jamais parlé de ça moi...
Moi ce que j'ai compris de cette phrase c'est que tu avais l'air de dire que tu as des pages P1, P2, P3 et que tu voulais que quand tu reviens en arrière de la page P2 à la page P1 par exemple, tu veux que P1 fasses un pushViewController(autreVC), c'est ça ?
Donc si tu veux que quand P1 apparaisse tu pousses un autre VC, pourquoi ne pas mettre le code qui appelle pushViewController(autreVC) dans le viewDidAppear de P1, de sorte que quand P1 apparaisse, ça fasse le push, puisque c'est exactement ce que tu avais l'air de demander ?
Après, si tu ne fais que ça dans ton viewDidAppear de P1, évidemment ça va aussi l'afficher au premier affichage de P1, même si ce n'est pas parce que tu reviens en arrière sur P1 alors que tu étais sur P2 avant.
Mais détecter ce cas particulier ne doit certainement pas se faire avec des Gestures pour moi, car ce n'est pas la bonne approche : déjà c'est bête de créer ton propre UIGestureRec plutôt que d'utiliser celui déjà existant de UIPageViewController, mais surtout, utiliser les Gestures ça répondrait au besoin : "je veux faire une action quand il y a telle Gesture" pas "quand il va à la page précédente". Qui te dit que demain l'utilisateur ne pourrait pas changer de page et aller à la page précédente par un autre moyen qu'avec la gesture du UIPageController ? Par exemple avec un tap sur le UIPageControl, typiquement...
Pour moi il faut plutôt que ton UIPageController garde par exemple le numéro de la dernière page affichée, ou une référence vers le dernier UIViewController affiché, et dans le viewDidAppear de chaque page, tu t'en sers pour regarder si la page d'où on vient est une page qui est après (genre "if (previousPageNumber > currentPageNumber)") ce qui voudrait dire qu'on est revenu en arrière, et donc que tu dois faire ton "pushViewControlelr(autreVC)".
Merci AliGator pour tes efforts.
Je reconnais que c'est confus.
Non :
Je veux, quand je suis en page P1 du pageView, tout simplement, allez dans un autre controller que le pageView en swipant comme si j'allais à la page précédente (qui n'existe pas, bien sur, car on est en P1).
Je suis carrément et absolument d'accord avec toi. C'est ce que je disais au début. Mais en essayant donc, comme ceci (bon, là c'est un popToRoot, car c'est vers le premier controller du projet, mais ce sera ensuite que des pushViews) :
Dans la méthode before
Et ça marche impeccable, mais le problème est que la méthode after (comme elle appelle aussi la méthode before), eh bien ne fait pas le after mais fait le before du premier écran et fait le popToRoot ou le push - C'est trop con comme truc.
En gros, comment aller de P1 (d'un pageView) au P5 (le dernier) d'un autre pageView ?
Et inversement, et aussi carrément, pourquoi pas d'un P1 vers vers un P3 d'un autre pageView ?
En tout cas, je vais creuser ton idée de
Bon j'ai placé :
dans la méthode "before"
et :
dans la méthode "after"
et le résultat est n'importe quoi.
Il répond quand il veut, et surtout pas toujours la même valeur - pfff
Donc impossible de faire un test là -dessus non plus, comme pour le controller.itemIndex.
Bon, je suis enfin presque près du but.
Avec les méthodes delegate.
Je peux aller dans les deux sens, mais après le P2 vers P1, il enchaine directement le popToRoot.
Je dois faire juste un p'tit réglages dans mes variables de contrôles.
Voici mon code. Qu'en penses-tu ?
Lien vidéo courte, plus loin.
Et une petite vidéo ici
A mon avis, Before ne correspond pas forcément à la page n-1, mais à une page située avant la page courante (n-quelque chose). De même pour After (n+quelque chose). Le UIPageView doit construire et détruire les pages à la volée, en fonction de la mémoire disponible et de la vitesse de lecture de l'utilisateur. Il peut très bien construire 2 ou 3 pages à l'avance, selon sa prédiction sur les demandes de l'utilisateur.
Enfin c'est juste une hypothése basée sur ce que j'ai vu du fonctionnement de UITableView, l'équivalent vertical de UIPageView.
Ouais, je pense un peu comme toi.
Je pense être sur la bonne voie, avec la méthode delegate et mes variables cafter" et "before".
Qu'en penses-tu ?
C'est correct au niveau d'apple ?
C'est un peu comme si tu implémentais une méthode "-(NSString*)currentUserName;" qui était sensée retourner le nom de l'utilisateur courant... dans le code de cette méthode tu ne vas pas présenter des VC ou chant des propriétés, ce n'est pas une méthode d'action mais une méthode qui est juste sensée retourner une valeur.
Si tu as des actions à prévoir (comme justement ton presentViewController ou autre), c'est dans la méthode de delegate adéquate qu'il faut le faire qui décrit quand il y a un changement de page
Ou alors effectivement maintenant y que je comprend un peu mieux ton besoin si la vraie demande c'est de faire un popToRoot quand on swipe vers la gauche alors qu'on est sur la page P1, s'attacher aux Gestures existantes du PVC.
Ouah.
Donc, ok, je suis ton conseil. Merci. Je ne savais pas tout ça.
Ce code de base est bon, quand même ?
Heu, j'ai cherché" sur le web, j'ai rien trouvé à part ça (sur la page d'apple), et je vois pas ce que je peux en faire.
je sais utiliser les gesture comme ça
et
Mais comment jouer avec les gesture sur un pageView ?
Bon, après avoir grillé un bon million de neurones, j'ai enfin réussi. Pfff.
C'est énervant, parce que c'est tout con, j'en étais sûr.
Voilà le code.
J'ajoute le gesture recognizer sur le premier écran du PVC :
Puis la fonction associée :
Et puis je remet les méthodes datasource :
Donc, encore merci pour le p'tit cours au passage.
Je met résolu