iOS Swift:UIPageViewController - 以编程方式翻页

Posted

技术标签:

【中文标题】iOS Swift:UIPageViewController - 以编程方式翻页【英文标题】:iOS Swift: UIPageViewController - Turning page programmatically 【发布时间】:2015-05-27 18:02:14 【问题描述】:

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

class ViewController: UIViewController, UIPageViewControllerDataSource 
...

现在我打算在页面上也提供上一个/下一个按钮,以便通过单击这些按钮来翻页。

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


注意

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

【问题讨论】:

Is it possible to Turn page programmatically in UIPageViewController? 的可能重复项 【参考方案1】:

通常没有必要摆弄页面索引等等。您可能已经在实现一个dataSource: UIPageViewControllerDataSource,它包含了显示上一个或下一个 ViewController 所需的所有内容。

Swift 5 示例:

extension UIPageViewController 

    func goToNextPage() 
       guard let currentViewController = self.viewControllers?.first else  return 
       guard let nextViewController = dataSource?.pageViewController( self, viewControllerAfter: 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, viewControllerBefore: currentViewController ) else  return 
       setViewControllers([previousViewController], direction: .reverse, animated: false, completion: nil)
    


这样您就可以保证您要转换到的页面正是PageViewController's 内置手势将触发的页面。

【讨论】:

我很难弄清楚如何使用您的想法更新presentationIndexForPageViewController。在我的pageItemViewController 上,我声明了一个名为itemIndex 的变量。我将如何在此扩展程序中设置它? 我使用带有计时器的 func goToNextPage() - 那么如何使用此方法滚动到带有计时器的下一页呢?这是我的问题的链接***.com/questions/45025088/… 救命稻草!!!非常感谢。我将发布 Swift 3 版本以供将来参考。 干得好,以我的拙见展示了 UPPageViewController 中的差距。 :) 快速说明:此方法似乎不会触发 UIPageViewControllerDelegate(:didFinishAnimating,但在使用手势分页时确实会调用它,这更像是一个错误而不是我怀疑的功能。【参考方案2】:

Swift 3 版本的SuitedSloth 的答案(对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)
    


【讨论】:

非常感谢! 很高兴它帮助了@WilliamT.Mallard 如果您要更新委托中的点,您可能希望使用此代码来完成(而不是 nil): completed in self.delegate?.pageViewController?(self, didFinishAnimating: true, previousViewControllers: [], transitionCompleted: completed) @Recusiwe 检查你上面的评论 嗨,谢谢你写这篇文章,这可能是一个愚蠢的问题,但是一旦我创建了 UIPageViewController 的扩展,我不应该能够在类 PageController 上调用它吗:UIPageViewController? (PageController 是名称)。如果我尝试这样做:PageController.goToNextPage(animated: true),我得到:实例成员 'goToNextPage' 不能用于类型 'PageController';您的意思是改用这种类型的值吗?【参考方案3】:

使用此功能并为您想要的动画设置过渡样式。

【讨论】:

JordanC> 我需要点击一个按钮来翻页 - 那么我如何使用上述功能呢? @Jasper 创建一个 UIButton,当它被点击时,你会在你的 UIPageViewController 中找出下一个页面,然后将该页面传递给 setViewControllers 方法。 我不知道为什么,但我得到了正确的页面,但如果我调用此方法,则没有任何变化。【参考方案4】:

这里也是带有代表的 swift 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) )

【讨论】:

【参考方案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) -&gt; UIViewController? 是我自己的函数,可以让正确的视图控制器滑动到。

【讨论】:

currentPageIndex 来自哪里? currentPageIndex 是您定义的本地变量,以便您可以跟踪当前页面。【参考方案6】:

如果有人想使用定义的协议来导航和以编程方式更改视图控制器,请把它留在这里。

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

使用上述协议并确认根 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()
    
    
    // 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 方法。

以下示例:按下按钮后调用委托方法

    class SecondViewController: UIViewController 
       
        var delegate: AppWalkThroughDelegate!
        
        override func viewDidLoad() 
           super.viewDidLoad()
        

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

【讨论】:

第二个例子,为什么要设置self.dataSource = self 可能是一个错误,但不应该在那里,感谢您指出这一点。 @JDerbs

以上是关于iOS Swift:UIPageViewController - 以编程方式翻页的主要内容,如果未能解决你的问题,请参考以下文章

ios 整理(一)swift和oc的区别

iOS-Swift-UIView

iOS开发中OC和swift的对比

ios OC、swift混编制作framework

iOS-swift-基础篇1

iOS开发系列--Swift 3.0