iOS Swift: UIPageViewController - перелистывание страниц программно

У меня есть UIPageViewController, который отлично работает, когда мы проводим влево или вправо, чтобы переворачивать страницы.

class ViewController: UIViewController, UIPageViewControllerDataSource {
...
}

Теперь я намерен также предоставить кнопку "Предыдущая/Следующая" на странице, чтобы можно было перелистывать страницы, нажимая эти кнопки.

Как я могу активировать поведение влево/вправо ИЛИ переворачивать страницы программно?


Заметка

Это вопрос к языку Swift, а не к Objective-C.

Ответ 1

Используйте это funtion и задайте стиль перехода для нужной анимации.

enter image description here

enter image description here

Ответ 2

Как правило, нет необходимости возиться с индексами страниц, а что нет. Скорее всего, вы уже реализуете dataSource: UIPageViewControllerDataSource, у которого есть все, что вам нужно, чтобы отобразить предыдущий или следующий ViewController.

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)

    }

}

Таким образом, вы гарантируете, что страницы, на которые вы переходите, - это именно то, что вызовет запуск PageViewController в жестов.

Ответ 3

Версия SuitedSloth от Swift 3 (с небольшим изменением animated параметра, так как мне нужно, чтобы он был анимирован по умолчанию, но все же принимал параметр в функции) на случай, если это кому-нибудь понадобится:

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)
    }

}

Ответ 4

Вот также быстрая реализация 4 с делегатами.

Так как я также использую UIPageViewControllerDelegate, и методы делегата не были вызваны с большинством решений setViewController.

Спасибо Эндрю Дункану за его комментарий о делегате.

// 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) })
}

Ответ 5

Вот краткая реализация этого:

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? - это моя собственная функция, чтобы получить правильный контроллер просмотра для прокрутки.

Ответ 6

Просто оставив это здесь, вы хотите, чтобы кто-то захотел использовать определенный протокол для навигации по нему и с программным изменением контроллеров представления.

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

Используйте вышеуказанный протокол и подтвердите root UIPageViewController для управления навигацией между контроллерами представлений.

Пример ниже:

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)
    }

    }

После достижения всего этого контроллеры детского представления, которые должны заставить UIPageViewController перемещаться на следующую или предыдущую страницу, могут использовать методы AppWalkThroughDelegate, передав определенный номер в свойство delegate.

Пример ниже: Метод делегата, который вызывается после нажатия кнопки

    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)
         }
    }

Ответ 7

    let orderedViewControllers = [UIViewController(),UIViewController(), UIViewController()]
    let pageViewController = UIPageViewController()
    let pageControl = UIPageControl()

    func jump(to: Int, completion: @escaping (_ vc: UIViewController?) -> Void){

        guard orderedViewControllers.count > to else{
            //index of bounds
            return
        }

        let toVC = orderedViewControllers[to]

        var direction: UIPageViewController.NavigationDirection = .forward

        if pageControl.currentPage < to {
            direction = .forward;
        } else {
            direction = .reverse;
        }

        pageViewController.setViewControllers([toVC], direction: direction, animated: true) { _ in
            DispatchQueue.main.async {
                self.pageViewController.setViewControllers([toVC], direction: direction, animated: false){ _ in
                    self.pageControl.currentPage = to
                        completion(toVC)

                }
            }
        }
    }

ИСПОЛЬЗОВАНИЕ:

self.jump(to: 5) { (vc) in
    // you can do anything for new vc.
}