UIPageViewController: retourne la vue visible courante

89

Comment savez-vous quelle est la page / vue actuelle affichée dans un UIPageViewController?

J'ai remplacé la viewDidAppearméthode de mes vues enfants, afin qu'elles envoient un identifiant à la vue parent dans leur viewDidAppearméthode.

Cependant, le problème est le suivant: je ne peux pas utiliser de manière fiable cet identifiant comme identifiant pour la page affichée. car si l'utilisateur tourne la page mais à mi-parcours décide d'arrêter le tournage et de remettre la page, il viewDidAppearaura déjà été appelé. (la vue est visible derrière la page enroulée).

Peut-être que je ne devrais passer à un nouvel identifiant que si la vue actuelle disparaît. Mais je me demande s'il n'y a pas un moyen plus simple de retourner la vue actuellement visible?

Jan
la source
Avez-vous essayé d'utiliser à la viewDidAppear:animated:place?
Jusqu'au
O Oui. J'ai utilisé ça. J'ai édité la question pour corriger mon erreur.
Jan
La façon dont vous avez édité la question n'a aucun sens pour moi. Soit vous envoyez cet identifiant depuis viewWillAppear ou depuis viewDidAppear. Veuillez revérifier votre modification.
Jusqu'au
Désolé, j'ai mal édité la question. J'ai toujours utilisé viewDidAppear. J'espère que ma dernière modification clarifie cela.
Jan
Jetez un oeil à ici les gars, cela fonctionne pour moi stackoverflow.com/a/36860663/4286947
theDC

Réponses:

103

Vous devez effectuer manuellement le suivi de la page actuelle. La méthode déléguée pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:vous indiquera quand mettre à jour cette variable. Le dernier argument de la méthode transitionCompleted:peut vous dire si un utilisateur a effectué une transition de changement de page ou non.

Ole Begemann
la source
1
+1 pour la bonne réponse - J'aurais aimé avoir la chance de travailler avec UIPageViewController et de prendre en charge iOS5 uniquement.
Jusqu'au
Merci, c'est exactement la solution propre que je recherchais. mieux que les délégués sur les pages.
Jan
3
Lorsque vous faites pivoter l'appareil, comment faites-vous le suivi de la page actuelle?
Satyam
@jusqu'à ce que vous puissiez, définissez simplement la version minimale de votre projet sur ios5.0
mtmurdock
83
Comment savoir s'il faut incrémenter ou décrémenter le numéro de page actuel?
shim le
59

Depuis iOS 6, j'ai constaté que la viewControllerspropriété d'UIPageViewController se mettait constamment à jour afin qu'elle contienne toujours le contrôleur de vue unique qui représente la page actuelle, et rien d'autre. Ainsi, vous pouvez accéder à la page actuelle en appelant viewControllers[0](en supposant que vous n'affichez qu'un seul contrôleur de vue à la fois).

Le tableau viewController ne se met à jour qu'une fois la page "verrouillée" en place, donc si un utilisateur décide de révéler partiellement la page suivante, elle ne devient pas la page "courante" à moins qu'il n'achève la transition.

Si vous souhaitez garder une trace des «numéros de page», attribuez à vos contrôleurs de vue une valeur d'index lorsque vous les créez via les méthodes de source de données UIPageViewController.


Donc par exemple:

-(void)autoAdvance
    {
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];

    if ( currentIndex >= (myViewControllers.count-1) ) return;

    [self setViewControllers:@[myViewControllers[ currentIndex+1 ]]
        direction:UIPageViewControllerNavigationDirectionForward
        animated:YES
        completion:nil];
    }
-(NSInteger)presentationIndexForPageViewController:
                         (UIPageViewController *)pageViewController
    {
    // return 0;
    UIViewController *currentVC = self.viewControllers[0];
    NSUInteger currentIndex = [myViewControllers indexOfObject:currentVC];
    return currentIndex;
    }

Mais notez les commentaires selon lesquels ce n'est pas fiable.

Eddy Borja
la source
2
Je l'ai trouvé peu fiable. Je n'ai pas pu trouver la source du problème. Lorsque l'animation se termine, j'accède à la viewControllerspropriété et j'obtiens les bons contrôleurs de vue, mais lorsque je tourne, sur la méthode spineLocationForInterfaceOrientation, je n'obtiens plus les bons contrôleurs de vue. Je me suis donc tenu à maintenir ma propre propriété currentPage au lieu de toujours compter sur le viewControllers.
Fábio Oliveira
Intéressant, je vais jouer un peu avec pour voir comment il se comporte dans ces cas particuliers
Eddy Borja
2
J'ai également trouvé qu'il n'était pas fiable. Il semble qu'Apple appelle simplement viewControllerBeforeViewController ou viewControllerAfterViewController pour chaque tour de page, mais ne met pas à jour UIPageViewController.viewControllers. Je ne sais pas comment ils réussissent toujours à se tromper dans ce genre de choses, mais ils le font. Cela augmente vraiment ma charge de travail et brise la clarté de mon code (en violant souvent DRY et d'autres principes).
Zack Morris
3
@ZackMorris. C'est absolument incroyable, vous avez tout à fait raison. C'est un «moment d'horreur Apple». Pourquoi oh pourquoi n'incluraient-ils pas les fonctions évidentes comme déplacer l'une vers la droite, sur quelle page suis-je actuellement, etc.
Fattie
1
self.viewControllers [0] semble bien fonctionner pour moi. Mais j'appelle juste setViewControllers une fois lors de l'initiation et j'ai laissé le reste à l'automatisation. (testé sous iOS 8.4)
Bob
45

Malheureusement, toutes les méthodes ci-dessus ne m'ont pas aidé. Néanmoins, j'ai trouvé la solution en utilisant des balises. Ce n'est peut-être pas le meilleur, mais cela fonctionne et j'espère que cela aidera quelqu'un:

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed 
{
    if (completed) {
        int currentIndex = ((UIViewController *)self.pageViewController.viewControllers.firstObject).view.tag;
        self.pageControl.currentPage = currentIndex;
    }
}

Dans Swift: (merci à @Jessy )

func pageViewController(pageViewController: UIPageViewController,
    didFinishAnimating finished: Bool,
    previousViewControllers: [UIViewController],
    transitionCompleted completed: Bool)
{
    guard completed else { return }
    self.pageControl.currentPage = pageViewController.viewControllers!.first!.view.tag
}

Exemple: gist

Victor
la source
3
Cela semble le plus simple et a bien fonctionné pour moi. J'ai défini les balises lors de l'ajout des contrôleurs de vue (par exemple, HelpPage1ViewController * page1 = [self.storyboard instantiateViewControllerWithIdentifier: @ "page1"]; page1.view.tag = 0;). Ensuite, vous pouvez définir une propriété currentPage pour le contrôleur de vue principal afin de garder une trace de votre position. Assurez-vous d'ajouter les deux protocoles ("<UIPageViewControllerDataSource, UIPageViewControllerDelegate>"), pas seulement la source de données, et définissez le délégué sur self ("self.pageViewController.delegate = self;") ou la méthode ne sera pas appelée. Cela m'a déconcerté un peu.
James Toomey
1
@VictorM cette solution ne fonctionne pas pour moi. J'ai un pageViewController avec différentes images. Il continue de renvoyer la balise 0 pour chaque balayage, une idée pourquoi cela se produit? Merci d'avance
theDC
1
@VictorM J'ai passé plusieurs jours à essayer de sauvegarder l'index, mais je trouve accidentellement cette réponse, j'aimerais pouvoir voter 1000 fois, merci!
Evgeniy Kleban
1
Excellente solution Merci d'avoir passé des heures à essayer de contourner ce
problème
Il ne renvoie qu'une valeur de 0. Suis-je en train de faire quelque chose de mal
N.Der le
35

S'appuyant sur la réponse d'Ole…

Voici comment j'ai implémenté les 4 méthodes pour suivre la page actuelle et mettre à jour l'indicateur de page avec l'index correct:

- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)[self.model count];

}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)self.currentIndex;
}

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{

    SJJeanViewController* controller = [pendingViewControllers firstObject];
    self.nextIndex = [self indexOfViewController:controller];

}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed){

        self.currentIndex = self.nextIndex;

    }

    self.nextIndex = 0;

}
Corey Floyd
la source
2
Je pense que la dernière ligne devrait être self.nextIndex = self.currentIndexplutôt que self.nextIndex = 0pour restaurer correctement l'index lorsqu'une transition n'est pas terminée. Sinon , vous risquez de se retrouver avec une currentIndexvaleur de 0 lorsque la pagination rapidement et - vient quelque part au milieu de vos pages.
hverlind
1
Cela ne fonctionne pas complètement pour moi. Parfois, pageViewController: willTransitionToViewControllers n'est pas appelé et donc nextIndex n'est pas modifié, et l'index actuel est alors erroné.
Hayden Holligan
31

La solution ci-dessous a fonctionné pour moi.

Apple pourrait éviter beaucoup de tracas en rendant la pagination de la vue par défilement UIPageViewController native plus configurable. J'ai dû recourir à la superposition d'un nouvel UIView et UIPageControl simplement parce que la pagination native UIPageViewController ne prend pas en charge un arrière-plan transparent ou un repositionnement dans le cadre de vue.

- (void)pageViewController:(UIPageViewController *)pvc didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
  if (!completed)
  {
    return;
  }
  NSUInteger currentIndex = [[self.pageViewController.viewControllers lastObject] index];
  self.pageControl.currentPage = currentIndex;
}
sirvine
la source
1
dans ce que vous entendez par index?
Yohan
J'obtiens l'index (c'est-à-dire l'entier qui représente la position du contrôleur de vue actuel dans le tableau de self.pageViewController.viewControllers), puis je l'utilise pour définir l'attribut currentPage de self.pageControl (qui attend une valeur entière) . Ça a du sens?
sirvine
6
index est une propriété personnalisée ici, je crois
Adam Johns
problème avec ceci est que si vous voulez changer de page sans la méthode d'animation ne sera pas appelée
Silviu St
19

Swift 4

Aucun code inutile. 3 façons de le faire. Utilisation de la méthode UIPageViewControllerDelegate .

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    guard completed else { return }

    // using content viewcontroller's index
    guard let index = (pageViewController.viewControllers?.first as? ContentViewController)?.index else { return }

    // using viewcontroller's view tag
    guard let index = pageViewController.viewControllers?.first?.view.tag else { return }

    // switch on viewcontroller
    guard let vc = pageViewController.viewControllers?.first else { return }
    let index: Int
    switch vc {
    case is FirstViewController:
        index = 0
    case is SecondViewController:
        index = 1
    default:
        index = 2
    }
}
Nikola Milicevic
la source
Dieu merci! Je ne savais pas pageViewController.viewControllers. Comment connaissez-vous viewControllers? .First est celui en question?
Script Kitty
Assez simple en fait, le tableau viewControllers contient uniquement le contrôleur de vue actuellement présenté.
Nikola Milicevic
2
comment accéder à la variable d'index depuis cette fonction?
N.Der
11

Je garde une trace de l'index de la page en utilisant une petite fonction et en spécifiant pageIndex comme NSInteger statique.

-(void) setPageIndex
{
    DataViewController *theCurrentViewController = [self.pageViewController.viewControllers objectAtIndex:0];

    pageIndex = [self.modelController indexOfViewController:theCurrentViewController];
}

et appeler [self setPageIndex];à l'intérieur de la fonction spécifiée par Ole et également après avoir détecté le changement d'orientation.

Wahib Ul Haq
la source
5

J'ai d'abord utilisé la solution de Corey mais cela ne fonctionnait pas sur iOS5 puis j'ai fini par utiliser,

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed{

    if(completed) {
        _currentViewController = [pageViewController.viewControllers lastObject];
    }
}

Il a essayé de passer d'une page à l'autre et cela fonctionne bien pour le moment.

Basit Ali
la source
3

Malheureusement, rien ci-dessus ne fonctionne pour moi.

J'ai deux contrôleurs de vue et quand je fais défiler légèrement (environ 20px) la dernière vue vers l'arrière, cela déclenche le délégué:

pageViewController:didFinishAnimating:previousViewControllers:transitionCompleted:

et dire que la page courante (index) est 0ce qui est faux.

Utilisation du délégué dans le viewController enfant quelque chose comme:

- (void)ViewController:(id)VC didShowWithIndex:(long)page;

// and a property

@property (nonatomic) NSInteger index;

qui est déclenché à l'intérieur viewDidAppearcomme:

- (void)viewDidAppear:(BOOL)animated
{
    ...

    [self.delegate ViewController:self didShowWithIndex:self.index];
}

A travaillé pour moi.

0yeoj
la source
3

Cela fonctionne pour moi de manière fiable

J'ai un UIPageController personnalisé. Cette pageController.currentPage est mise à jour à partir du UIViewController affiché dans la vueWillAppear

   var delegate: PageViewControllerUpdateCurrentPageNumberDelegate?

      init(delegate: PageViewControllerUpdateCurrentPageNumberDelegate ){
        self.delegate = delegate
        super.init(nibName: nil, bundle: nil)
      }

      required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
      }

    override func viewWillAppear(animated: Bool) {

        if delegate != nil {
          self.delegate!.upateCurrentPageNumber(0) //(0) is the pageNumber corresponding to the displayed controller
        }
      } 

    //In the pageViewController 

    protocol PageViewControllerUpdateCurrentPageNumberDelegate {

      func upateCurrentPageNumber(currentPageIndex: Int)
    }

     create the view display controllers initializing with the delegate

    orderedViewControllers = {
              return [
                IntroductionFirstPageViewController(delegate: self),
                IntroductionSecondPageViewController(delegate: self),
                IntroductionThirdPageViewController(delegate: self)
              ]

            }()

    the function implementing the protocol

    func upateCurrentPageNumber(currentPageIndex: Int){
        pageControl.currentPage = currentPageIndex
      }
lguerra10
la source
1

J'utilise view.tagdepuis un moment maintenant, essayer de garder une trace de la page actuelle était trop compliqué.

Dans ce code, l'index est stocké dans la tagpropriété de chacun viewet est utilisé pour récupérer le VC suivant ou précédent. En utilisant cette méthode, il est également possible de créer un défilement infini. Consultez le commentaire dans le code pour afficher également cette solution:

extension MyPageViewController: UIPageViewControllerDataSource {

  func viewControllerWithIndex(var index: Int) -> UIViewController! {
    let myViewController = storyboard?.instantiateViewControllerWithIdentifier("MyViewController") as MyViewController

    if let endIndex = records?.endIndex {
      if index < 0 || index >= endIndex { return nil }
      // Instead, We can normalize the index to be cyclical to create infinite scrolling
      // if index < 0 { index += endIndex }
      // index %= endIndex
    }

    myViewController.view.tag = index
    myViewController.record = records?[index]

    return myViewController
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index + 1)
  }

  func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
    let index = viewController.view?.tag ?? 0
    return viewControllerWithIndex(index - 1)
  }

  func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
    return records?.count ?? 0
  }

  func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
    return (pageViewController.viewControllers.first as? UIViewController)?.view.tag ?? 0
  }
}
Yariv Nissim
la source
1

Merci pour votre réponse les gars, j'ai rencontré un problème similaire, j'ai dû stocker l'index. Je modifie légèrement mon code, collez-le ci-dessous:

- (MenuListViewController *)viewControllerAtIndex:(NSInteger)index {

    if (_menues.count < 1)
        return nil;

    //    MenuListViewController *childViewController = [MenuListViewController initWithSecondSetFakeItems];
    MenuListViewController *childViewController = self.menues[index];
    childViewController.index = index;

    return childViewController;
}

#pragma mark - Page View Controller Data Source

- (void)pageViewController:(UIPageViewController *)pageViewController
        didFinishAnimating:(BOOL)finished
   previousViewControllers:(NSArray<UIViewController *> *)previousViewControllers
       transitionCompleted:(BOOL)completed{

    if (completed) {

        NSUInteger currentIndex = ((MenuListViewController *)self.pageController.viewControllers.firstObject).index;
        NSLog(@"index %lu", (unsigned long)currentIndex);
    }
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger index = [(MenuListViewController *)viewController index];

    if (index == 0)
        return nil;

    index --;

    return [self viewControllerAtIndex:index];
}


- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{

    NSUInteger index = [(MenuListViewController *)viewController index];

    index ++;

    if (index == _menues.count)
        return nil;

    return [self viewControllerAtIndex:index];
}
Evgeniy Kleban
la source
0
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {

    NSLog(@"Current Page = %@", pageViewController.viewControllers);

    UIViewController *currentView = [pageViewController.viewControllers objectAtIndex:0];

    if ([currentView isKindOfClass:[FirstPageViewController class]]) {
             NSLog(@"First View");
        }
        else if([currentView isKindOfClass:[SecondPageViewController class]]) {
             NSLog(@"Second View");
        }
        else if([currentView isKindOfClass:[ThirdViewController class]]) {
              NSLog(@"Third View");
        }
}

//pageViewController.viewControllers always return current visible View ViewController
Avinash
la source
0

Ci-dessous le code de démonstration (dans Swift 2) qui montre comment cela est fait en implémentant un simple tutoriel de balayage d'image. Commentaires dans le code lui-même:

import UIKit

/*
VCTutorialImagePage represents one page show inside the UIPageViewController.
You should create this page in your interfacebuilder file:
- create a new view controller
- set its class to VCTutorialImagePage
- sets its storyboard identifier to "VCTutorialImagePage" (needed for the loadView function)
- put an imageView on it and set the contraints (I guess to top/bottom/left/right all to zero from the superview)
- connect it to the "imageView" outlet
*/

class VCTutorialImagePage : UIViewController {
    //image to display, configure this in interface builder
    @IBOutlet weak var imageView: UIImageView!
    //index of this page
    var pageIndex : Int = 0

    //loads a new view via the storyboard identifier
    static func loadView(pageIndex : Int, image : UIImage) -> VCTutorialImagePage {
        let storyboard = UIStoryboard(name: storyBoardHome, bundle: nil)
        let vc = storyboard.instantiateViewControllerWithIdentifier("VCTutorialImagePage") as! VCTutorialImagePage
        vc.imageView.image      = image
        vc.pageIndex            = pageIndex
        return vc
    }
}


/*
VCTutorialImageSwiper takes an array of images (= its model) and displays a UIPageViewController 
where each page is a VCTutorialImagePage that displays an image. It lets you swipe throught the 
images and will do a round-robbin : when you swipe past the last image it will jump back to the 
first one (and the other way arround).

In this process, it keeps track of the current displayed page index
*/

class VCTutorialImageSwiper: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    //our model = images we are showing
    let tutorialImages : [UIImage] = [UIImage(named: "image1")!, UIImage(named: "image2")!,UIImage(named: "image3")!,UIImage(named: "image4")!]
    //page currently being viewed
    private var currentPageIndex : Int = 0 {
        didSet {
            currentPageIndex=cap(currentPageIndex)
        }
    }
    //next page index, temp var for keeping track of the current page
    private var nextPageIndex : Int = 0


    //Mark: - life cylce


    override func viewDidLoad() {
        super.viewDidLoad()
        //setup page vc
        dataSource=self
        delegate=self
        setViewControllers([pageForindex(0)!], direction: .Forward, animated: false, completion: nil)
    }


    //Mark: - helper functions

    func cap(pageIndex : Int) -> Int{
        if pageIndex > (tutorialImages.count - 1) {
            return 0
        }
        if pageIndex < 0 {
            return (tutorialImages.count - 1)
        }
        return pageIndex
    }

    func carrouselJump() {
        currentPageIndex++
        setViewControllers([self.pageForindex(currentPageIndex)!], direction: .Forward, animated: true, completion: nil)
    }

    func pageForindex(pageIndex : Int) -> UIViewController? {
        guard (pageIndex < tutorialImages.count) && (pageIndex>=0) else { return nil }
        return VCTutorialImagePage.loadView(pageIndex, image: tutorialImages[pageIndex])
    }

    func indexForPage(vc : UIViewController) -> Int {
        guard let vc = vc as? VCTutorialImagePage else {
            preconditionFailure("VCPagImageSlidesTutorial page is not a VCTutorialImagePage")
        }
        return vc.pageIndex
    }


    //Mark: - UIPageView delegate/datasource


    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        return pageForindex(cap(indexForPage(viewController)+1))
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        return pageForindex(cap(indexForPage(viewController)-1))
    }

    func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) {
        nextPageIndex = indexForPage(pendingViewControllers.first!)
    }

    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
        if !finished { return }
        currentPageIndex = nextPageIndex
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int {
        return tutorialImages.count
    }

    func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int {
        return currentPageIndex
    }

}
HixField
la source
0

J'ai un tableau viewControllers, que j'affiche dans UIPageViewController .

extension MyViewController: UIPageViewControllerDataSource {

func presentationCount(for pageViewController: UIPageViewController) -> Int {
    return self.viewControllers.count
}

func presentationIndex(for pageViewController: UIPageViewController) -> Int {
    return self.currentPageIndex
}
}




extension MyViewController: UIPageViewControllerDelegate {

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

    if !completed { return }

    guard let viewController = previousViewControllers.last, let index = indexOf(viewController: viewController) else {
        return
    }

    self.currentPageIndex = index

}

fileprivate func indexOf(viewController: UIViewController) -> Int? {
    let index = self.viewControllers.index(of: viewController)
    return index
}
}

Chose importante à noter est que la setViewControllers méthode de UIPageViewController ne donne pas de rappel de délégué. Les rappels délégués représentent uniquement les actions tactiles de l'utilisateur dans UIPageViewController .

Jarora
la source
0

Voici la solution que j'ai trouvée:

class DefaultUIPageViewControllerDelegate: NSObject, UIPageViewControllerDelegate {

    // MARK: Public values
    var didTransitionToViewControllerCallback: ((UIViewController) -> Void)?

    // MARK: Private values
    private var viewControllerToTransitionTo: UIViewController!

    // MARK: Methods
    func pageViewController(
        _ pageViewController: UIPageViewController,
        willTransitionTo pendingViewControllers: [UIViewController]
    ) {
        viewControllerToTransitionTo = pendingViewControllers.last!
    }

    func pageViewController(
        _ pageViewController: UIPageViewController,
        didFinishAnimating finished: Bool,
        previousViewControllers: [UIViewController],
        transitionCompleted completed: Bool
    ) {
        didTransitionToViewControllerCallback?(viewControllerToTransitionTo)
    }
}

Usage:

 let pageViewController = UIPageViewController()
 let delegate = DefaultUIPageViewControllerDelegate()

 delegate.didTransitionToViewControllerCallback = {
    pageViewController.title = $0.title
 }

 pageViewController.title = viewControllers.first?.title
 pageViewController.delegate = delegate

Assurez-vous de définir le titre initial

Peter Combee
la source
0

La façon la plus simple d'aborder cette IMHO est d'utiliser le PageControl pour stocker le résultat potentiel de la transition, puis revenir si la transition a été annulée. Cela signifie que le contrôle de la page change dès que l'utilisateur commence à balayer, ce qui me convient. Cela nécessite que vous ayez votre propre tableau de UIViewControllers (dans cet exemple appelé allViewControllers)

func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
    if let index = self.allViewControllers.index(of: pendingViewControllers[0]) {
        self.pageControl.currentPage = index
    }
}

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    if !completed, let previousIndex = self.allViewControllers.index(of: previousViewControllers[0]) {
        self.pageControl.currentPage = previousIndex
    }
}
taylor rapide
la source
0

Que diriez-vous de demander un viewControllerdirectement à partir de la UIPageViewController(version Swift 4):

fileprivate weak var currentlyPresentedVC: UIViewController?

func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
    currentlyPresentedVC = pageViewController.viewControllers?.first
}

Ou, si vous avez simplement besoin du contrôleur de vue actuellement présenté à un moment donné, utilisez simplement pageViewController.viewControllers?.firstà ce moment-là.

Milan Nosáľ
la source
0

Dans Swift 5 et après la réponse de sirvine

extension InnerDetailViewController: UIPageViewControllerDelegate {

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {

        if completed {
            guard let newIndex = embeddedViewControllers.firstIndex(where: { $0 == pageViewController.viewControllers?.last }) else { return }
            print(newIndex)
            currentEmbeddedViewControllerIndex = newIndex
        }

    }

} 

Dans ce cas, je me fiche de la classe d'UIViewController intégrée

Reimond Hill
la source
-1
UIViewController *viewController = [pageViewController.viewControllers objectAtIndex:0];
NSUInteger currentIndex = [(ViewController*) viewController indexNumber];

Il renverra l'index de la page actuelle. et doit utiliser ce code sous la fonction déléguée de UIPageViewController (didFinishAnimating).

Vinay Podili
la source