我一直在开发一个简单的测试应用程序,以了解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 firstViewController
,secondViewController
和thirdViewController
中使用的标签和图像。
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)方法(viewControllerBeforeViewController
和viewControllerAfterViewController
)提供数组。这是
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/