web-dev-qa-db-fra.com

Utilisation de UIPageViewController avec Swift et plusieurs contrôleurs de vue

J'essaie d'utiliser une UIPageViewController dans une application Swift avec plusieurs contrôleurs de vue. J'ai 2 contrôleurs de vue sur mon scénario (firstViewController et secondViewController) qui sont tous deux intégrés dans leurs propres contrôleurs de navigation. Ils ont des identifiants de storyboard "FirstViewController" et "SecondViewController". J'ai également un contrôleur de vue de page sur mon storyboard avec le contrôleur identifierPageView et je règle la navigation sur horizontal et le style de transition pour faire défiler l'inspecteur d'attributs. FirstViewController est le contrôleur de vue racine de l'application

Je veux que firstViewController soit la première page du contrôleur de vue de page, de sorte que j'ai écrit sa classe comme suit:

import Foundation
import UIKit

class FirsttViewController: UITableViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate  {

    override func viewDidLoad() {

        let pageViewController: PageViewController = self.storyboard.instantiateViewControllerWithIdentifier("PageViewController") as PageViewController

        pageViewController.delegate = self

        var viewControllers: [UIViewController] = [self]

        pageViewController.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)
        pageViewController.view.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)

        self.addChildViewController(pageViewController)
        self.view.addSubview(pageViewController.view)
        pageViewController.didMoveToParentViewController(self)


    }
    func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {


        let secondViewController: SecondViewController = self.storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as SecondViewController


        return secondViewController
    }

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

        return nil
    }

    func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
        return 2
    }

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

le fichier pour SecondViewController ressemble à ceci:

import Foundation
import UIKit

class SecondViewController: UITableViewController, UIPageViewControllerDataSource {

    func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {

        return nil
    }

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

        let firstViewController: FirstViewController = self.storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController
        return firstViewController
    }

}

Cependant, lorsque je lance mon application, elle ne semble pas avoir de contrôleur de visualisation de page. Il montre simplement firstViewController et c'est tout. Pas de points, pas de pages, etc. Quelqu'un sait ce qui ne va pas? J'ai trouvé quelques didacticiels Objective-C, mais ils traitent tous de l'utilisation d'un seul contrôleur de vue pour toutes les pages et ont un contrôleur de vue racine qui n'est pas une page dans la variable pageView. J'espérais que cela ressemblerait à l'utilisation d'une tabBarController dans laquelle vous cliqueriez et glisseriez sur les contrôleurs de vue, mais ce n'est malheureusement pas le cas. Comme je l'ai dit, je n'ai jamais travaillé avec l'un de ces appareils auparavant, alors je suis un peu perdu.

mettre à jour:

suivant la suggestion de iiFreeman, j’ai sous-classé UIPageViewController et en ai fait la racine de mon fichier de storyboard. ci-dessous est la sous-classe

import Foundation
import UIKit
class PageViewController: UIPageViewController {

    override func viewDidLoad() {

        let startingViewController = self.storyboard.instantiateViewControllerWithIdentifier("FirstViewController") as FirstViewController

        self.dataSource = startingViewController
        var viewControllers: [UIViewController] = [startingViewController]

        self.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)



    }

}

Cependant, l’application se bloque maintenant sur un écran noir et finalement, Xcode perd la connexion au simulateur. Je ne suis pas vraiment sûr de ce qui se passe.

17
Stone Preston

OK, j'ai compris. Comme j'avais besoin du contrôleur de vue de page pour être la racine et tout gérer, j'ai sous-classé UIPageViewController comme iiFreeman a suggéré et conforme aux protocoles de délégué et de source de données. J'ai ensuite configuré le contrôleur dans viewDidLoad et mis en œuvre les méthodes de délégué et de source de données. J'ai ajouté à un magasin de propriétés un tableau d'identifiants de storyboard ainsi qu'un autre permettant de suivre l'index actuel de ce tableau. J'ai également ajouté une méthode d'assistance pour renvoyer le bon contrôleur de vue à partir d'un index. Je n'avais besoin de rien dans mes autres sous-classes de contrôleur tableView puisque mon contrôleur d'affichage de page gérait tout. Une chose que j’ai réalisée c’est que, puisque ma tableViewControllers était intégrée à des contrôleurs de navigation, mon contrôleur de visualisation de page devait afficher les contrôleurs de navigation, et non les contrôleurs tableView. ci-dessous est ma mise en œuvre:

import Foundation
import UIKit

class PageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate {

    var index = 0
    var identifiers: NSArray = ["FirstNavigationController", "SecondNavigationController"]
    override func viewDidLoad() {

        self.dataSource = self
        self.delegate = self

        let startingViewController = self.viewControllerAtIndex(self.index)
        let viewControllers: NSArray = [startingViewController]
        self.setViewControllers(viewControllers, direction: UIPageViewControllerNavigationDirection.Forward, animated: false, completion: nil)



    }

    func viewControllerAtIndex(index: Int) -> UINavigationController! {

        //first view controller = firstViewControllers navigation controller
        if index == 0 {

            return self.storyboard.instantiateViewControllerWithIdentifier("FirstNavigationController") as UINavigationController

        }

        //second view controller = secondViewController's navigation controller
        if index == 1 {

            return self.storyboard.instantiateViewControllerWithIdentifier("SecondNavigationController") as UINavigationController
        }

        return nil
    }
    func pageViewController(pageViewController: UIPageViewController!, viewControllerAfterViewController viewController: UIViewController!) -> UIViewController! {

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier)

        //if the index is the end of the array, return nil since we dont want a view controller after the last one
        if index == identifiers.count - 1 {

            return nil
        }

        //increment the index to get the viewController after the current index
        self.index = self.index + 1
        return self.viewControllerAtIndex(self.index)

    }

    func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {

        let identifier = viewController.restorationIdentifier
        let index = self.identifiers.indexOfObject(identifier)

        //if the index is 0, return nil since we dont want a view controller before the first one
        if index == 0 {

            return nil
        }

        //decrement the index to get the viewController before the current one
        self.index = self.index - 1
        return self.viewControllerAtIndex(self.index)

    }


    func presentationCountForPageViewController(pageViewController: UIPageViewController!) -> Int {
        return self.identifiers.count
    }

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

}

ce post m'a beaucoup aidé

32
Stone Preston

sure cause FirstViewController - contrôleur de vue initial dans votre storyboard

ajoutez une sous-classe UIPageViewController personnalisée dans votre story-board, marquez-la comme initiale et faites tout le travail à l'intérieur, instanciez les membres du contrôleur de page par des storyboard dans votre sous-classe UIPageViewController, faites la même chose dans une autre classe

1
iiFreeman

Sachez que ce code ne fonctionnera qu'avec deux ViewController. Si vous envisagez d’utiliser davantage, vous devez modifier la ligne: 

self.index = self.index + 1

Trouvé à l'avant et après l'appel, à:

self.index = index + 1

Pour appeler l'index ViewController actuel.

1