如何在 UIPageViewcontroller 中添加两个视图控制器
Posted
技术标签:
【中文标题】如何在 UIPageViewcontroller 中添加两个视图控制器【英文标题】:how to add two view controllers in UIPageViewcontroller 【发布时间】:2013-04-04 09:14:28 【问题描述】:我在 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;
【问题讨论】:
如果您只想显示一页,则需要通过 dataSource 一次提供一页,这就是您的应用崩溃的原因 - 它有两个页面可以在预期的时候显示(在纵向模式下)我猜)。向我们展示您的委托和数据源代码。 当然老兄......但应用程序在 viewDidLoad 中崩溃 为什么setViewControllers:direction:animated:completion
在你传递多个数组时会崩溃,它会获取一个数组?传入数组一定有其他用例吗?
@BrianMorearty -setViewControllers:direction:animated:completion:
接受一个数组,这样当主干位置设置为UIPageViewControllerSpineLocationMid
时,就可以传入两个视图控制器。否则,只需要一个视图控制器。这确实应该在文档中更明确地指出。
【参考方案1】:
问题是您将一个包含两个视图控制器的数组传递给页面视图控制器,而它一次只需要一个,请将您的数组更改为:
NSArray *viewControllers = @[appDelegate.firstViewController];
您将传递其中一个视图,但 viewControllerAfterViewController
和 viewControllerBeforeViewController
将处理其余的视图。
【讨论】:
如果只需要一个视图控制器,为什么这个调用的参数是一个数组? @Shoerob 根据文档For transition style 'UIPageViewControllerTransitionStylePageCurl', if 'doubleSided' is 'YES' and the spine location is not 'UIPageViewControllerSpineLocationMid', two view controllers must be included, as the latter view controller is used as the back.
【参考方案2】:
啊..终于解决了同样的问题..,它可能会帮助你..
当我们将书脊位置设置为UIPageViewControllerSpineLocationMid
时,pageViewController 的doubleSided
属性会自动设置为YES。这意味着页面正面的内容不会部分显示在背面。但是当这个属性设置为NO时,页面正面的内容会部分地从背面显示出来,给页面一种半透明的效果。所以,在竖屏时,我们必须将值设置为NO,否则会导致异常。
因此,在您的 UIPageviewcontroller
委托方法中,当您将 spinLocation 返回为 UIPageViewControllerSpineLocationMid
时,在 else 部分中将此 doubleSided
属性添加为 YES
self.pageViewController.doubleSided = YES;
return UIPageViewControllerSpineLocationMid;
【讨论】:
【参考方案3】:self.pageViewController.doubleSided = NO;
return UIPageViewControllerSpineLocationMid;
这是异常的解决方案。
在 xcode it self 中你可以找到这个。
转到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];
这将在您切换时为页面过渡设置动画。
【讨论】:
以上是关于如何在 UIPageViewcontroller 中添加两个视图控制器的主要内容,如果未能解决你的问题,请参考以下文章
如何在 UIPageViewController 中更改页面指示器的背景颜色
如何在 UIPageviewcontroller 中实现静态菜单栏?
如何在视图中移动 UIPageViewController 页面控制器按钮的位置
如何在 UIPageViewcontroller 中添加两个视图控制器