UIPageViewController 不跟踪页面索引

Posted

技术标签:

【中文标题】UIPageViewController 不跟踪页面索引【英文标题】:UIPageViewController not keeping track of page index 【发布时间】:2015-08-16 10:04:09 【问题描述】:

我整个周末都在为这个问题苦苦挣扎,并且花了很长时间在谷歌上搜索以找到解决方案,但没有任何成功。

我的用例非常简单,我无法相信要让这种微不足道的行为正常工作是多么困难。

我的应用是一个简单的分页流程,用户可以向左或向右滑动以查看下一页或上一页。我有一个 UIPageViewController,每个页面都包含一个 UITableView。由于此处解释的原因,我在尝试跟踪 viewControllerAfterViewController 和 viewControllerBeforeViewController 函数中的页面索引时遇到了问题:PageViewController delegate functions called twice

我已经尝试按照所有建议的解决方法来解决这个问题(跟踪 willTransitionToViewControllers 和 didFinishAnimating 中的索引)但这并不能解决我的问题,因为 viewController*ViewController 函数仍然必须返回一个 viewController,因为它们最初是调用了两次,第一个返回的 viewController 似乎是被使用的那个,第二个 pass through 似乎没有任何影响。

虽然我已经看到很多关于这个问题的问题和博客,但我还没有看到一个示例来说明如何从 viewController*ViewController 函数中始终如一地返回正确的 viewController,并且非常感谢您提供示例。我看不到解决方案的主要问题是,如果我只有一个 viewController,其内容在页面加载时动态更新,如何确定 willTransitionToViewControllers 中的下一个索引。对我来说,这似乎是一个先有鸡还是先有蛋的问题。我需要弄清楚要使用哪些内容来更新页面,但要做到这一点,我需要知道页面的索引是什么(这是内容的一部分)。

编辑 以下是受影响代码的精简版:

- (void)viewDidLoad 
     [super viewDidLoad];

     _pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
     _pageViewController.dataSource = self;
     _pageViewController.delegate = self;
     [self.view addSubview:_pageViewController.view];

     PageContentViewController *startingPage = [self viewControllerAtIndex:0];

     NSArray *viewControllers = @[startingPage];
     [_pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:nil];



- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController 
     // Don't do any index calculations as the result is inconsistent
     return [self viewControllerAtIndex:nextIndex];


- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController 
     // Don't do any index calculations as the result is inconsistent
     return [self viewControllerAtIndex:nextIndex];


- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers 
     // This value never changes because the global _pageViewContentController hasn't been updated yet
     nextIndex = [((PageContentViewController *)pendingViewControllers[0]) pageIndex];


- (PageContentViewController *)viewControllerAtIndex:(NSUInteger)index 
     _pageContentViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageContentViewController"];
     _pageContentViewController.pageIndex = index;
     _pageContentViewController.title = index;

     return _pageContentViewController;

我已经调试了调用这些函数的顺序,并希望在页面转换后使用正确的数据填充全局 _pageViewContentController。

编辑 2 提供有关我的问题的更多详细信息;我的每个页面都包含一个标题和一个网络链接表。单击链接会打开一个 WebViewController 以显示选定的网页。使用以下 Yunus 的解决方案,一切都正确显示(标题和链接按预期显示)但是当单击链接时出现问题,因为这会从下一页加载链接。页面的渲染阶段似乎发生在数据正确的地方,但是在渲染完成后它会用不正确的数据重新初始化页面内容控制器,这就是实际链接数据错误的原因(即使渲染的数据是好的)。

【问题讨论】:

你能分享一些你的代码的相关部分吗? @YunusErenGuzel - 添加了代码 sn-ps。 如何打开这个WebViewController?在 UIPageViewController 内部还是作为模态等等? 哇——令人惊奇的是,描述您的问题如何让您以全新的眼光看待它!我意识到我正在我的页面内容视图控制器的 viewDidLoad 函数中初始化我的网络链接。这导致渲染的数据与控制器内的实际数据不同。我只是删除了该初始化,现在一切都按预期工作。感谢您围绕尤努斯提出想法 - 它帮助我以不同的方式解决问题。 很高兴您解决了您的问题;) 【参考方案1】:

让我们将所有相关的 contentViewControllers 保存在一个数组中

self.contentViewControllers = [NSMutableArray new];
for(int i=0; i< MAX_INDEX; i++) 
  [self.contentViewControllers addObject:[self viewControllerAtIndex:0]];

那么我们需要做的是决定我们应该在方法之后和之前显示哪个视图控制器

- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
  viewControllerBeforeViewController:(UIViewController *)viewController


  for(int i=0;i<self.contentViewControllers.count ;i++)
  
    if(viewController == [self.contentViewControllers objectAtIndex:i])
    
      if(i-1 >= 0)
      
        return [self.contentViewControllers objectAtIndex:i-1];
      
    
  
  return nil;


- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
       viewControllerAfterViewController:(UIViewController *)viewController


  for(int i=0;i<self.contentViewControllers.count ;i++)
  
    if(viewController == [self.contentViewControllers objectAtIndex:i])
    
      if(i+1 < self.contentViewControllers.count)
      
        return [self.contentViewControllers objectAtIndex:i+1];
      
    
  
  return nil;

然后在过渡方法中

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers

  UIViewController* viewController = [pendingViewControllers objectAtIndex:0];
  NSInteger nextIndex = [self.contentViewControllers indexOfObject:viewController];
  [self.pageControl setCurrentPage:nextIndex];

【讨论】:

你好尤努斯。谢谢你的帮助。我已经修改了我的代码以尝试您的建议(这是我在周末已经尝试过但没有成功的方法)。在您的示例中,您正在设置 nextIndex 值,但它从未在任何地方使用。我在这里错过了什么吗? 其实我留空给你,你想怎么用都可以。我将它与 SMPageControl 一起使用以保持索引与 [self.pageControl setCurrentPage:nextIndex]; 你可以使用这个 ViewController 来看看它是如何工作的。 github.com/yunuserenguzel/sonicraph-ios/blob/master/sonicraph/… 你的代码给了我同样的问题。当我调试时,这是事件的顺序: 1. 应用程序加载 2. 滑动到下一页 3. 调用 viewControllerAfterViewController 4. 调用 viewControllerBeforeViewController 5. 调用 willTransitionToViewControllers 6. 调用 viewControllerAfterViewController 7. 显示下一页但不正确由于对 viewController*ViewController 的额外调用而产生的数据 这不是好的解决方案,因为您存储了所有 viewControllers 实例。 UIPageViewController 应该在委托方法中管理它。如果你有很多页面,这种方法效率很低。

以上是关于UIPageViewController 不跟踪页面索引的主要内容,如果未能解决你的问题,请参考以下文章

swift+UIPageViewController 纯代码实现引导页

如何设置 UIPageViewController(分页类型)手势委托

UIPageViewController制作小说翻页效果

UIPageViewController:如何添加非分页工具栏或其他“覆盖”元素?

UIPageViewController:每页更改页面指示器/页面控件的颜色

在两页模式下如何实现可缩放的 UIPageViewController?