我一直在开发一个简单的测试应用程序,以了解UIPageViewController的来龙去脉。我有它的工作,但我不相信我的执行是最好的方法。我希望你们中的一些人能指出我正确的方向。

为了获得基本的了解,我以本教程为起点。
http://www.appcoda.com/uipageviewcontroller-storyboard-tutorial/

本教程创建了一个应用程序,该应用程序为viewController呈现的每个页面使用一个UIPageViewController。但是,我需要利用UIPageViewController来滚动具有完全不同的布局的页面。因此,为了使本教程更进一步,我创建了一个主从应用程序,该应用程序在详细信息 View 中使用UIPageViewController来显示三个不同的 View Controller 。我坚持只显示此测试应用程序的图像和标签,但是我当前正在构建的应用程序具有三个viewControllers,它们将包含tableview,imageView和textViews或某些textFields。

这是我的测试应用程序的 Storyboard 。

我将DetailViewController用作PageViewController的数据源。在DVC的viewDidLoad中,我以这种方式建立将在三个内容 View Controller firstViewControllersecondViewControllerthirdViewController中使用的标签和图像。

if ([[self.detailItem description] isEqualToString:@"F14's"]) {
    //Here the page titles and images arrays are created
    _pageTitles = @[@"Grim Reapers", @"Breakin the Barrier!", @"Top Gun"];
    _pageImages = @[@"F14_Grim.jpg", @"F14boom.jpg", @"F14_topgun.jpg"];

    //Here I call a method to instantiate the viewControllers
    FirstController *selectedController = [self viewControllerAtIndex:0];
    SecondController *nextController = [self viewControllerAtIndex:1];
    ThirdController *lastController = [self viewControllerAtIndex:2];
    [_vc addObject:selectedController];
    [_vc addObject:nextController];
    [_vc addObject:lastController];
    _vc1 = @[selectedController];


} else if ([[self.detailItem description] isEqualToString:@"F35's"]){
    //code is above is repeated

下面是实例化viewControllers的方法
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
    if (([self.pageTitles count] == 0) || (index >= [self.pageTitles count])) {
        return nil;
    }

    // Create a new view controller and pass suitable data.
    if (index == 0) {
        FirstController *fvc = [self.storyboard instantiateViewControllerWithIdentifier:@"FirstPageController"];
        fvc.imageFile = self.pageImages[index];
        fvc.titleText = self.pageTitles[index];
        fvc.pageIndex = index;
        if ([_vc count]) {
             //Here I have to replace the viewController each time it is recreated
             [_vc replaceObjectAtIndex:0 withObject:fvc];
        }
        return fvc;
    } else if (index == 1) {
//Code is repeated for remaining viewControllers
viewDidLoad中的代码是我觉得自己需要做的工作之一。我不认为加载DVC时需要实例化所有三个 View Controller ,但是我不知道如何为UIPageViewControllerDataSource协议(protocol)方法(viewControllerBeforeViewControllerviewControllerAfterViewController)提供数组。

这是viewControllerBefore..方法。
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{

    NSUInteger index = [_vc indexOfObject:viewController];

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

    index--;

    //notice here I call my instantiation method again essentially duplicating work I have already done!
    return [self viewControllerAtIndex:index];
}

总而言之,似乎每次从一个页面滑动到另一页面时,我都不必要地重新创建 View Controller 。这仅仅是pageViewController的工作方式,还是让我复杂化了整个过程。任何输入都会很棒!

解决方案

Matt建议使用标识符一个非常简单的解决方案。在我的 Storyboard 中,我只是选中了将我已经实现的 Storyboard 标识符用作恢复标识符的框

然后在viewDidLoad中,而不是创建一个viewControllers数组,只需创建一个与恢复标识符匹配的字符串数组即可。
if ([[self.detailItem description] isEqualToString:@"F14's"]) {
    _pageTitles = @[@"Grim Reapers", @"Breakin the Barrier!", @"Top Gun"];
    _pageImages = @[@"F14_Grim.jpg", @"F14boom.jpg", @"F14_topgun.jpg"];
    FirstController *selectedController = [self viewControllerAtIndex:0];
    [_vc addObject:@"FirstPageController"];
    [_vc addObject:@"SecondPageController"];
    [_vc addObject:@"ThirdPageController"];
    _vc1 = @[selectedController];

最后,要确定委托(delegate)方法中的索引,请执行此操作,而不是我之前做的事情:
NSString * ident = viewController.restorationIdentifier;
NSUInteger index = [_vc indexOfObject:ident];

现在,它可以工作,而不必不必要地实例化 View Controller 。

最后要注意的是,如果有人正在使用我在此处所提供的功能,则可以摆脱viewControllerAtIndex:方法中的以下代码片段。
if ([_vc count]) {
     //Here I have to replace the viewController each time it is recreated
     [_vc replaceObjectAtIndex:0 withObject:fvc];
}

最佳答案

首先,您绝对正确,构成UIPageViewController的“页面”的 View Controller 在本质上可以完全不同。什么也没有说它们必须是同一 View Controller 类的实例。

现在让我们解决实际的问题,即您非常明智地需要一种方法,以给定当前 View Controller 来提供下一个或上一个 View Controller 。这的确是使用页面 View Controller 时的主要问题。

拥有一个 View Controller 数组并不是真的很糟糕。毕竟, View Controller 是轻量级的对象(它是重量级对象的 View )。但是,您对这一问题的处理方式似乎很笨拙,这也是对的。

我的建议是:如果要将 View Controller 实例保存在 Storyboard 中,那为什么不只保留其标识符数组呢?现在,您有了一个由三个字符串组成的数组。你有多简单?您还需要一个实例变量,该变量跟踪哪个标识符对应于将其 View 用作当前页面的 View Controller (以便可以确定哪个标识符是“下一个”或“上一个”);这可能只是数组的整数索引。

这样,每次用户“翻页”时实例化 View Controller 绝对没有错。那是需要 View Controller 时应该做的。您可以通过标识符轻松地执行此操作。

最后,请注意,如果您使用页面 View Controller 的滚动样式,则甚至不必这样做,因为页面 View Controller 会缓存 View Controller 并停止调用委托(delegate)方法(或者至少调用它们更少) 。

关于ios - 如何实现利用多个ViewController的UIPageViewController,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21641373/

10-13 09:04