web-dev-qa-db-fra.com

iOS Swift: UIPageViewController - Tournage de page par programme

J'ai un UIPageViewController, qui fonctionne bien lorsque nous glissons vers la gauche ou la droite pour tourner les pages.

class ViewController: UIViewController, UIPageViewControllerDataSource {
...
}

Maintenant, j'ai l'intention de fournir le bouton Précédent/Suivant sur la page également, afin que les pages puissent être tournées en cliquant sur ces boutons.

Comment puis-je déclencher le comportement de balayage gauche/droite OR tourner les pages par programme?


Remarque

Ceci est une question pour Swift langage, pas Objective-C.

23
Jasper

Utilisez cette fonction et définissez le style de transition pour l'animation souhaitée.

enter image description here

enter image description here

9
JordanC

Il n'est généralement pas nécessaire de jouer avec les index de page et ce qui ne l'est pas. Il y a de fortes chances que vous implémentiez déjà un dataSource: UIPageViewControllerDataSource, qui contient tout ce dont vous avez besoin pour afficher un ViewController précédent ou suivant.

Exemple Swift 2.2:

extension UIPageViewController {

    func goToNextPage(){

        guard let currentViewController = self.viewControllers?.first else { return }

        guard let nextViewController = dataSource?.pageViewController( self, viewControllerAfterViewController: currentViewController ) else { return }

        setViewControllers([nextViewController], direction: .Forward, animated: false, completion: nil)

    }


    func goToPreviousPage(){

        guard let currentViewController = self.viewControllers?.first else { return }

        guard let previousViewController = dataSource?.pageViewController( self, viewControllerBeforeViewController: currentViewController ) else { return }

        setViewControllers([previousViewController], direction: .Reverse, animated: false, completion: nil)

    }

}

De cette façon, vous êtes assuré que les pages vers lesquelles vous effectuez la transition sont exactement ce que déclencheraient les gestes intégrés de PageViewController.

47
SuitedSloth

La version Swift 3 de la réponse de SuitedSloth (avec un petit ajustement au paramètre animated comme je avait besoin qu'il soit animé par défaut, mais en prenant toujours un paramètre dans la fonction) au cas où quelqu'un en aurait besoin:

extension UIPageViewController {

    func goToNextPage(animated: Bool = true) {
        guard let currentViewController = self.viewControllers?.first else { return }
        guard let nextViewController = dataSource?.pageViewController(self, viewControllerAfter: currentViewController) else { return }
        setViewControllers([nextViewController], direction: .forward, animated: animated, completion: nil)
    }

    func goToPreviousPage(animated: Bool = true) {
        guard let currentViewController = self.viewControllers?.first else { return }
        guard let previousViewController = dataSource?.pageViewController(self, viewControllerBefore: currentViewController) else { return }
        setViewControllers([previousViewController], direction: .reverse, animated: animated, completion: nil)
    }

}
20
Gligor

Voici l'implémentation Swift 4 avec les délégués également.

Étant donné que j'utilise également UIPageViewControllerDelegate et que les méthodes déléguées n'ont pas été appelées avec la plupart des solutions setViewController.

Merci à Andrew Duncan's pour son commentaire sur le délégué.

// Functions for clicking next and previous in the navbar, Updated for Swift 4
@objc func toNextArticle(){
    guard let currentViewController = self.viewControllers?.first else { return }

    guard let nextViewController = dataSource?.pageViewController( self, viewControllerAfter: currentViewController ) else { return }

    // Has to be set like this, since else the delgates for the buttons won't work
    setViewControllers([nextViewController], direction: .forward, animated: true, completion: { completed in self.delegate?.pageViewController?(self, didFinishAnimating: true, previousViewControllers: [], transitionCompleted: completed) })
}

@objc func toPreviousArticle(){
    guard let currentViewController = self.viewControllers?.first else { return }

    guard let previousViewController = dataSource?.pageViewController( self, viewControllerBefore: currentViewController ) else { return }

    // Has to be set like this, since else the delgates for the buttons won't work
    setViewControllers([previousViewController], direction: .reverse, animated: true, completion:{ completed in self.delegate?.pageViewController?(self, didFinishAnimating: true, previousViewControllers: [], transitionCompleted: completed) })
}
7
Vasco

Voici une implémentation Swift de ceci:

private func slideToPage(index: Int, completion: (() -> Void)?) {
    let count = //Function to get number of viewControllers
    if index < count {
        if index > currentPageIndex {
            if let vc = viewControllerAtIndex(index) {
                self.pageViewController.setViewControllers([vc], direction: UIPageViewControllerNavigationDirection.Forward, animated: true, completion: { (complete) -> Void in
                    self.currentPageIndex = index
                    completion?()
                })
            }
        } else if index < currentPageIndex {
            if let vc = viewControllerAtIndex(index) {
                self.pageViewController.setViewControllers([vc], direction: UIPageViewControllerNavigationDirection.Reverse, animated: true, completion: { (complete) -> Void in
                    self.currentPageIndex = index
                    completion?()
                })
            }
        }
    }
}

viewControllerAtIndex(index: Int) -> UIViewController? est ma propre fonction pour faire glisser le contrôleur de vue correct.

5
Swinny89

Le fait de laisser cela ici au cas où quelqu'un voudrait utiliser un protocole défini pour naviguer et modifier les contrôleurs de vue par programmation.

@objc protocol AppWalkThroughDelegate {
  @objc optional func goNextPage(forwardTo position: Int)
  @objc optional func goPreviousPage(fowardTo position: Int)
}

Utilisez le protocole ci-dessus et confirmez pour rooter UIPageViewController pour gérer la navigation entre les contrôleurs de vue.

Exemple ci-dessous:

class AppWalkThroughViewController: UIPageViewController, UIPageViewControllerDataSource, AppWalkThroughDelegate {

    // Add list of view controllers you want to load

    var viewControllerList : [UIViewControllers] = {
       let firstViewController = FirstViewController()
       let secondViewController = SecondViewController() 
       // Assign root view controller as first responder
       secondViewController.delegate = self  

       let thirdViewController = ThirdViewController() 

    }

    override func viewDidLoad() {
       super.viewDidLoad()
       self.dataSource = self
    }

    // Navigate to next page 
    func goNextPage(fowardTo position: Int) {
       let viewController = self.viewControllerList[position]
       setViewControllers([viewController], direction: 
       UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
    }

    }

Une fois tout cela atteint, les contrôleurs de vue enfant qui doivent faire passer UIPageViewController à la page suivante ou précédente peuvent utiliser les méthodes AppWalkThroughDelegate en passant un nombre spécifique à la propriété déléguée.

Exemple ci-dessous: méthode déléguée invoquée une fois le bouton enfoncé

    class SecondViewController: UIViewController {

        var delegate: AppWalkThroughDelegate!

        override func viewDidLoad() {
           super.viewDidLoad()
           self.dataSource = self
        }

         @IBAction func goNextPage(_ sender: Any) {
            // Can be any number but not outside viewControllerList bounds 
            delegate.goNextPage!(fowardTo: 2)
         }
    }
1
Sharkes Monken