如何在UIPageViewController中添加两个视图控制器

32

我正在iPad上使用UIPageViewController,需要在第一页显示firstviewController,在横向布局下的下一页显示ContentViewController

如果我将NSArray设置为两个viewControllers,应用程序会在[self.pagviewController setViewController:]处崩溃,并出现以下异常:

提供的视图控制器数量(2)与所请求的书脊位置(UIPageViewControllerSpineLocationMin)所需数量(1)不匹配

以下是代码:

#pragma mark - UIPageViewControllerDataSource Methods

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController 
      viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
    if(currentIndex == 0)
    {
        return nil;
    }
    ContentViewController *contentViewController = [[ContentViewController alloc] init];
    contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex - 1];
    return contentViewController;
}

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
       viewControllerAfterViewController:(UIViewController *)viewController
{
    NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)viewController textContents]];
    if(currentIndex == self.modelArray.count-1)
    {
        return nil;
    }
    ContentViewController *contentViewController = [[ContentViewController alloc] init];
    contentViewController.textContents = [self.modelArray objectAtIndex:currentIndex + 1];

    return contentViewController;
}




//#pragma mark - UIPageViewControllerDelegate Methods

- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
                   spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation
{
    if(UIInterfaceOrientationIsPortrait(orientation))
    {
        //Set the array with only 1 view controller
        UIViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
        NSArray *viewControllers = [NSArray arrayWithObject:currentViewController];

        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

        //Important- Set the doubleSided property to NO.
        self.pageViewController.doubleSided = NO;
        //Return the spine location
        return UIPageViewControllerSpineLocationMin;
    }
    else
    {
        NSArray *viewControllers = nil;
        ContentViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];

        NSUInteger currentIndex = [self.modelArray indexOfObject:[(ContentViewController *)currentViewController textContents]];
        if(currentIndex == 0 || currentIndex %2 == 0)
        {
            UIViewController *nextViewController = [self pageViewController:self.pageViewController viewControllerAfterViewController:currentViewController];
            viewControllers = [NSArray arrayWithObjects:currentViewController, nextViewController, nil];
        }
        else
        {
            UIViewController *previousViewController = [self pageViewController:self.pageViewController viewControllerBeforeViewController:currentViewController];
            viewControllers = [NSArray arrayWithObjects:previousViewController, currentViewController, nil];
        }
        //Now, set the viewControllers property of UIPageViewController
        [self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:NULL];

        return UIPageViewControllerSpineLocationMid;
    }
}
- (void)viewDidLoad
{
    [super viewDidLoad];

    appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
    //Instantiate the model array
    self.modelArray = [[NSMutableArray alloc] init];
    self.vcs = [[NSMutableArray alloc]init];

    for (int index = 1; index <= 2 ; index++)
    {
        [self.modelArray addObject:[NSString stringWithFormat:@"Page %d",index]];
    }

    //Step 1
    //Instantiate the UIPageViewController.
    self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
                                                              navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal options:nil];
    //Step 2:
    //Assign the delegate and datasource as self.
    self.pageViewController.delegate = self;
    self.pageViewController.dataSource = self;

    //Step 3:
    //Set the initial view controllers.

    appDelegate.contentViewController.textContents = [self.modelArray objectAtIndex:0];


    NSArray *viewControllers = [NSArray arrayWithObjects:appDelegate.firstViewController,appDelegate.contentViewController,nil];
    [self.pageViewController setViewControllers:viewControllers
                                      direction:UIPageViewControllerNavigationDirectionForward
                                       animated:NO
                                     completion:nil];

    //Step 4:
    //ViewController containment steps
    //Add the pageViewController as the childViewController
    [self addChildViewController:self.pageViewController];

    //Add the view of the pageViewController to the current view
    [self.view addSubview:self.pageViewController.view];

    //Call didMoveToParentViewController: of the childViewController, the UIPageViewController instance in our case.
    [self.pageViewController didMoveToParentViewController:self];

    //Step 5:
    // set the pageViewController's frame as an inset rect.
    CGRect pageViewRect = self.view.bounds;
    pageViewRect = CGRectInset(pageViewRect, 40.0, 40.0);
    self.pageViewController.view.frame = pageViewRect;

    //Step 6:
    //Assign the gestureRecognizers property of our pageViewController to our view's gestureRecognizers property.
    self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
}

1
如果您只想显示一页,那么您需要通过dataSource逐页提供页面,这就是为什么您的应用程序崩溃的原因 - 当期望显示一个页面时(我猜测是在纵向模式下),它却有两个页面要显示。请向我们展示您的delegate和dataSource代码。 - Filip Radelic
1
当然,伙计……但是应用程序在viewDidLoad时崩溃了。 - user578386
4
为什么 setViewControllers:direction:animated:completion 这个方法需要传递一个数组,但是如果传递超过一个视图控制器会导致崩溃?这个方法肯定还有其他使用场景,可以用数组传入参数吗? - Brian Morearty
1
@BrianMorearty -setViewControllers:direction:animated:completion: 接受一个数组,因此当脊柱位置设置为 UIPageViewControllerSpineLocationMid 时,可以传入恰好两个视图控制器。否则,只期望传入一个视图控制器。这在文档中应该更明确地指出。 - sbrun
4个回答

27

问题在于你将包含两个视图控制器的数组传递给了页面视图控制器,而它一次只能接受一个视图控制器,请将你的数组改为以下形式:


问题在于你将包含两个视图控制器的数组传递给了页面视图控制器,而它一次只能接受一个视图控制器,请将你的数组改为以下形式:
NSArray *viewControllers = @[appDelegate.firstViewController];

你将通过其中一个视图,但是viewControllerAfterViewControllerviewControllerBeforeViewController会处理其余的视图。


11
为什么这个调用的参数是一个数组,如果它只需要一个视图控制器? - Shoerob
10
根据文档,对于转场样式为“UIPageViewControllerTransitionStylePageCurl”的情况,如果“doubleSided”是“YES”,并且书脊位置不是“UIPageViewControllerSpineLocationMid”,则必须包括两个视图控制器,因为后一个视图控制器将用作背面。 - Aleks N.

2
啊..终于找到了解决这个问题的方法,它可能会对你有所帮助。
当我们将书脊位置设置为UIPageViewControllerSpineLocationMid时,pageViewControllerdoubleSided属性会自动设置为YES。这意味着页面前面的内容不会部分显示在后面。但是,当此属性设置为NO时,页面前面的内容将部分显示在后面,使页面具有半透明的效果。因此,在纵向方向上,我们必须将值设置为NO,否则会导致异常。
因此,在您的UIPageviewcontroller委托方法中,在else部分添加此doubleSided属性,当您返回UIPageViewControllerSpineLocationMid作为书脊位置时,请将其设置为YES。
self.pageViewController.doubleSided = YES;
return UIPageViewControllerSpineLocationMid;

0
self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMid;

这是异常的解决方案。

在Xcode中,您可以找到它。

转到UIPageViewcontroller类,您可以看到如下解释:

@property (nonatomic, readonly) UIPageViewControllerSpineLocation spineLocation; // If transition style is 'UIPageViewControllerTransitionStylePageCurl', default is 'UIPageViewControllerSpineLocationMin', otherwise 'UIPageViewControllerSpineLocationNone'.

// Whether client content appears on both sides of each page. If 'NO', content on page front will partially show through back.
// If 'UIPageViewControllerSpineLocationMid' is set, 'doubleSided' is set to 'YES'. Setting 'NO' when spine location is mid results in an exception.
@property (nonatomic, getter=isDoubleSided) BOOL doubleSided; // Default is 'NO'.

-4

不必实现完整的数据源,您可以每次用户按下“下一个”或“返回”按钮时,将PageViewController设置为一次一个视图控制器,例如

[pageViewController setViewControllers:@[contentViewController]
                             direction:UIPageViewControllerNavigationDirectionForward
                              animated:YES
                            completion:nil];

这将在您切换时为页面转换添加动画效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接