Swift ios 不确定如何连接或使用嵌入式 UIPageViewController

Swift ios not sure on how to connect or use an embedded UIPageViewController

我决定放弃我的 UIImageView 并使用 UIPageViewController 以便用户可以在同一页面上的图像之间滑动。

我现在拥有的是一个普通的 UIViewController,因为我添加了一个 containerView,其中嵌入了一个 UIPageViewController。

因此 UIPageViewController 充当 viewcontroller 的子视图。

我有一个 "details" 页面,其中包含有关产品 X 的一些信息。我不希望只显示一张图片,而是希望图片 "swipeable" 以便用户可以看到不同的图片。但我不希望 PageControllerView 充当全尺寸视图,图像应该始终在 viewcontroller 中可见。

我现在的问题是卡住了。我不知道如何连接两个控制器。因此,如果有人有使用 swift 嵌入 segues/child 视图的示例 app/tutorial,请分享。

感谢下面的回答,我找到了解决方案:

在我的故事板中,我有 3 个 VC。 VC1 带有与 UIPageControllerView 有连接的嵌入式容器视图,然后我添加了第三个 VC "content view controller" 来显示 UIPageControllerView 的图像。

ViewController.swift

import UIKit

class ViewController: UIViewController, UIPageViewControllerDataSource {

    var pageViewController: UIPageViewController!
    var pageTitles: NSArray!
    var pageImages: NSArray!

    override func viewDidLoad()
    {
        super.viewDidLoad()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func restartAction(sender: AnyObject)
    {
        var startVC = self.viewControllerAtIndex(0) as ContentViewController
        var viewControllers = NSArray(object: startVC)

        self.pageViewController.setViewControllers(viewControllers as [AnyObject], direction: .Forward, animated: true, completion: nil)
    }

    func viewControllerAtIndex(index: Int) -> ContentViewController
    {
        if ((self.pageTitles.count == 0) || (index >= self.pageTitles.count)) {
            return ContentViewController()
        }

        var vc: ContentViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ContentViewController") as! ContentViewController

        vc.imageFile = self.pageImages[index] as! String
        vc.titleText = self.pageTitles[index] as! String
        vc.pageIndex = index

        return vc


    }


    // MARK: - Page View Controller Data Source

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

        var vc = viewController as! ContentViewController
        var index = vc.pageIndex as Int


        if (index == 0 || index == NSNotFound)
        {
            return nil

        }

        index--
        return self.viewControllerAtIndex(index)

    }

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

        var vc = viewController as! ContentViewController
        var index = vc.pageIndex as Int

        if (index == NSNotFound)
        {
            return nil
        }

        index++

        if (index == self.pageTitles.count)
        {
            return nil
        }

        return self.viewControllerAtIndex(index)

    }

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

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



    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "PageViewControllerFitta" {
            self.pageTitles = NSArray(objects: "Explore", "Today Widget")
            self.pageImages = NSArray(objects: "page1", "page2")

            let toView = segue.destinationViewController as! UIPageViewController
            toView.dataSource = self


            var startVC = self.viewControllerAtIndex(0) as ContentViewController
            var viewControllers = NSArray(object: startVC)

            toView.setViewControllers(viewControllers as [AnyObject], direction: .Forward, animated: true, completion: nil)

            toView.view.frame = CGRectMake(0, 30, self.view.frame.width, self.view.frame.size.height - 60)

            self.addChildViewController(toView)
            self.view.addSubview(toView.view)
            toView.didMoveToParentViewController(self)
        }
    }


}

ContentViewController.Swift

import UIKit

class ContentViewController: UIViewController {

    @IBOutlet weak var imageView: UIImageView!

    var pageIndex: Int!
    var imageFile: String!



    override func viewDidLoad()
    {
        super.viewDidLoad()

        self.imageView.image = UIImage(named: self.imageFile)


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }



}

嵌入实际上是一种在实例化包含控制器后立即发生的转场,因此实现此目的的方法是在包含控制器上实现 prepareForSegue,并捕获对子控制器的引用该方法中的控制器。这是一个改编自我目前正在从事的项目的示例,它可能无法编译,但应该让您了解如何继续进行——如果您需要更多信息,请告诉我。

为了让它工作,你必须给 segue 属性 一个 identifier。假设您正在使用故事板,这只是 segue 本身的一个 属性(位于连接父和子 UIViewController 的箭头上的小圆形过渡图标)。

class ViewController: UIViewController { // <-- this is the container

    var myEmbeddedViewController: MyCustomUIViewController?

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        switch segue.identifier {
        case .Some("the-identifier-i-used-for-the-segue"):
            myEmbeddedViewController = segue.destinationViewController as? MyCustomUIViewController
        default:
            break
        }
    }

    // ... other UIViewController stuff...
}

尽管在 Objective-C 而不是 Swift 中提供,但这是另一个涉及一些细节和文档的答案:iOS Nested View Controllers view inside UIViewController's view?


现在您已经有了对您的 UIPageControllerView 的引用,它需要一种方法来回答一些用于显示目的的问题:有多少页,我们打开到什么页,我什么时候显示什么页用户滑动到下一页和上一页。它使用一个常见的 UIKit/Cocoa 惯用语 dataSource 来做到这一点(很多视图控制器都有这个 属性)。

在您 link 的示例代码中,viewDidLoad 方法包含行 self.pageViewController.dataSource = self。这是可行的,因为作者声明他的 ViewController 除了扩展 UIViewController 外,还符合 UIPageViewControllerDataSource 协议。然后他实现了所需的方法:

func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController?
func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
func presentationCountForPageViewController(pageViewController: UIPageViewController) -> Int
func presentationIndexForPageViewController(pageViewController: UIPageViewController) -> Int

参见:https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UIPageViewControllerDataSourceProtocolRef/index.html

dataSource 不必是您的 ViewController,您可以创建一个单独的 class 或结构。不过,对于简单的示例,它可能没问题。)

您面临的具体挑战是根据您的应用程序的要求实施这些方法,以便嵌入式 UIPageViewController 可以根据您设置的内容确定要显示的内容 dataSource

假设您希望它显示一个 ProductImageViewController,它只需要一张图片和一个标签。从理论上讲,您可以为每个产品创建故事板,但除非您拥有少量永不更改的产品,否则这不会真正奏效。更有可能的是,您希望根据您的产品列表在代码中创建新实例。

在示例代码中,作者只是设置了一个标签和图像的静态数组,然后 pageViewController 方法只是根据当前位置和滑动方向从数组中抓取适当的一个。您想要设置一个数据源来了解您的产品列表,您可能从一些动态来源(如 CoreData、CloudKit 或其他一些 Web 服务)获得该列表。

作为一个让您自己熟悉的简单实验,请尝试修改该演示的变量 self.pageTitlesself.pageImages,看看这会如何改变嵌入式控制器的行为。尝试修改该代码,而不是使用两个数组,一个文本和一个图像文件名,而是使用包含您定义的结构或 class 的单个数组,它包含标签文本和文件名.一旦它开始工作,改变它而不是对 labels/images 的列表进行硬编码,而是从您的产品目录加载它。那是什么在起作用,你已经完成了,发货:)