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?
Ceci est une question pour Swift langage, pas Objective-C.
Utilisez cette fonction et définissez le style de transition pour l'animation souhaitée.
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.
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)
}
}
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) })
}
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.
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)
}
}