iOS Swift:UIPageViewController - 以编程方式转换页面

时间:2015-05-27 18:02:14

标签: ios swift uiviewcontroller uipageviewcontroller

我有一个UIPageViewController,当我们向左或向右滑动以翻页时它可以正常工作。

class ViewController: UIViewController, UIPageViewControllerDataSource {
...
}

现在我打算在页面上提供上一页/下一页按钮,这样就可以通过点击这些按钮来翻页。

如何触发向左/向右滑动或以编程方式翻页?

注意

这是 Swift 语言的问题,而不是Objective-C。

6 个答案:

答案 0 :(得分:46)

通常没有必要摆弄页面索引,什么不是。您可能已经实现了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内置手势所触发的页面。

答案 1 :(得分:19)

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

}

答案 2 :(得分:9)

使用此功能并为所需动画设置过渡样式。

enter image description here

enter image description here

答案 3 :(得分:7)

这也是与委托一起的快速4实现。

由于我还使用了UIPageViewControllerDelegate,因此大多数setViewController解决方案都没有调用委托方法。

感谢Andrew Duncan's对代表的评论。

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

答案 4 :(得分: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?是我自己的功能,可以让正确的视图控制器滑动到。

答案 5 :(得分:1)

只要将此保留在此处,任何人都希望使用已定义的协议进行导航并以编程方式更改视图控制器。

@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移动到下一页或上一页的子视图控制器可以通过将特定数字传递给delegate属性来使用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)
         }
    }