从 UIPageViewController 中删除视图控制器 [英] Removing a view controller from UIPageViewController

查看:24
本文介绍了从 UIPageViewController 中删除视图控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

奇怪的是,没有直接的方法可以做到这一点.考虑以下场景:

It's odd that there's no straightforward way to do this. Consider the following scenario:

  1. 您有一个包含 1 个页面的页面视图控制器.
  2. 添加另一个页面(共 2 个)并滚动到该页面.
  3. 我想要的是,当用户滚动回第一页时,第二页现在被删除并释放,用户无法再滑动回该页面.
  1. You have a page view controller with 1 page.
  2. Add another page (total 2) and scroll to it.
  3. What I want is, when the user scrolls back to the first page, the 2nd page is now removed and deallocated, and the user can no longer swipe back to that page.

我尝试在转换完成后将视图控制器作为子视图控制器删除,但它仍然让我滚动回空白页面(它不会调整"页面视图的大小)

I've tried removing the view controller as a child view controller after the transition is completed, but it still lets me scroll back to the empty page (it doesn't "resize" the page view)

我想做的事情可行吗?

推荐答案

虽然这里的答案都提供了信息,但还有一种处理问题的替代方法,这里给出:

While the answers here are all informative, there is an alternate way of handling the problem, given here:

UIPageViewController 使用滚动过渡样式导航到错误页面

当我第一次搜索这个问题的答案时,我搜索的措辞方式让我对这个问题感到震惊,而不是我刚刚链接到的那个,所以我觉得有必要发布一个链接到这个问题的答案另一个问题,现在我已经找到了,并且还详细说明了一点.

When I first searched for an answer to this problem, the way I was wording my search wound me up at this question, and not the one I've just linked to, so I felt obligated to post an answer linking to this other question, now that I've found it, and also elaborating a little bit.

matt 这里很好地描述了这个问题:

The problem is described pretty well by matt here:

这其实是 UIPageViewController 的一个 bug.它只发生在滚动样式 (UIPageViewControllerTransitionStyleScroll) 和调用后 setViewControllers:direction:animated:completion: with动画:是的.因此有两种解决方法:

This is actually a bug in UIPageViewController. It occurs only with the scroll style (UIPageViewControllerTransitionStyleScroll) and only after calling setViewControllers:direction:animated:completion: with animated:YES. Thus there are two workarounds:

不要使用 UIPageViewControllerTransitionStyleScroll.

Don't use UIPageViewControllerTransitionStyleScroll.

或者,如果您调用 setViewControllers:direction:animated:completion:,请使用仅动画:否.

Or, if you call setViewControllers:direction:animated:completion:, use only animated:NO.

要清楚地看到错误,请调用setViewControllers:direction:animated:completion: 然后,在界面(作为用户),向左(返回)导航到上一页手动.您将导航回错误的页面:不是前面的页面,但你当时所在的页面setViewControllers:direction:animated:completion: 被调用.

To see the bug clearly, call setViewControllers:direction:animated:completion: and then, in the interface (as user), navigate left (back) to the preceding page manually. You will navigate back to the wrong page: not the preceding page at all, but the page you were on when setViewControllers:direction:animated:completion: was called.

bug 的原因似乎是,当使用滚动样式, UIPageViewController 做某种内部缓存.因此,在调用 setViewControllers:direction:animated:completion: 之后,它无法清除其内部缓存.它认为它知道什么前一页是.因此,当用户向左导航到上一页,UIPageViewController 调用数据源失败方法 pageViewController:viewControllerBeforeViewController:, 或使用错误的当前视图控制器调用它.

The reason for the bug appears to be that, when using the scroll style, UIPageViewController does some sort of internal caching. Thus, after the call to setViewControllers:direction:animated:completion:, it fails to clear its internal cache. It thinks it knows what the preceding page is. Thus, when the user navigates leftward to the preceding page, UIPageViewController fails to call the dataSource method pageViewController:viewControllerBeforeViewController:, or calls it with the wrong current view controller.

这是一个很好的描述,不是这个问题中提到的问题,但非常接近.请注意关于如果您使用 animated:NO 执行 setViewControllers 您将强制 UIPageViewController 下次用户使用手势平移时重新查询其数据源的行,因为它没有不再知道它在哪里"或其当前视图控制器旁边的视图控制器.

This is a good description, not quite the problem noted in this question but very close. Note the line about if you do setViewControllers with animated:NO you will force the UIPageViewController to re-query its data source next time the user pans with a gesture, as it no longer "knows where it is" or what view controllers are next to its current view controller.

但是,这对我不起作用,因为有时我需要通过动画以编程方式移动 PageView.

However, this didn't work for me because there were times when I need to programmatically move the PageView around with an animation.

所以,我的第一个想法是使用动画调用 setViewControllers,然后在完成块中再次使用当前显示的视图控制器调用该方法,但没有动画.所以用户可以平移,很好,但随后我们再次调用该方法以重置页面视图.

So, my first thought was to call setViewControllers with an animation, and then in the completion block call the method again with whatever view controller was now showing, but with no animation. So the user can pan, fine, but then we call the method again to get the page view to reset.

不幸的是,当我尝试时,我开始从页面视图控制器中收到奇怪的断言错误".它们看起来像这样:

Unfortunately when I tried that I started getting strange "assertion errors" from the page view controller. They look something like this:

*** 断言失败 -[UIPageViewController queueingScrollView: ...

*** Assertion failure in -[UIPageViewController queuingScrollView: ...

不知道为什么会发生这种情况,我回溯并最终开始使用 Jai 的答案 作为解决方案,创建了一个完全新建 UIPageViewController,将其推到 UINavigationController 上,然后弹出旧的.很糟糕,但它有效——主要是.我发现 UIPageViewController 仍然偶尔出现断言失败,就像这样:

Not knowing exactly why this was happening, I backtracked and eventually started using Jai's answer as a solution, creating an entirely new UIPageViewController, pushing it onto a UINavigationController, then popping out the old one. Gross, but it works--mostly. I have been finding I'm still getting occasional Assertion Failures from the UIPageViewController, like this one:

*** 断言失败 -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:],/SourceCache/UIKit_Sim/UIKit-2380.17/UIPageViewController.m:1820 $1 =154507824 没有视图控制器管理可见视图 >

*** Assertion failure in -[UIPageViewController queuingScrollView:didEndManualScroll:toRevealView:direction:animated:didFinish:didComplete:], /SourceCache/UIKit_Sim/UIKit-2380.17/UIPageViewController.m:1820 $1 = 154507824 No view controller managing visible view >

然后应用程序崩溃了.为什么?嗯,搜索,我发现这个其他问题我在上面提到了,特别是 接受的答案,它提倡我最初的想法,简单地调用 setViewControllers: animation:YES 然后一旦它使用相同的视图控制器完成调用 setViewControllers:animated:NO 以重置 UIPageViewController,但它缺少元素:在主队列上调用该代码!代码如下:

And the app crashes. Why? Well, searching, I found this other question that I mentioned up top, and particularly the accepted answer which advocates my original idea, of simply calling setViewControllers: animated:YES and then as soon as it completes calling setViewControllers: animated:NO with the same view controllers to reset the UIPageViewController, but it had the missing element: calling that code back on the main queue! Here's the code:

__weak YourSelfClass *blocksafeSelf = self;     
[self.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:^(BOOL finished){
            if(finished)
            {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [blocksafeSelf.pageViewController setViewControllers:viewControllers direction:UIPageViewControllerNavigationDirectionForward animated:NO completion:NULL];// bug fix for uipageview controller
                });
            }
        }];

哇!这对我来说真正有意义的唯一原因是因为我观看了 WWDC 2012 Session 211,在 iOS 上构建并发用户界面(可用 此处 使用开发帐户).我现在回想起来,尝试修改 UIKit 对象(如 UIPageViewController)所依赖的数据源对象,并在辅助队列上进行修改,可能会导致一些严重的崩溃.

Wow! The only reason this actually made sense to me is because I have watched the the WWDC 2012 Session 211, Building Concurrent User Interfaces on iOS (available here with a dev account). I recall now that attempting to modify data source objects that UIKit objects (like UIPageViewController) depend on, and doing it on a secondary queue, can cause some nasty crashes.

我从未见过特别记录但现在必须假设情况并继续阅读的是,动画的完成块是在辅助队列上执行的,而不是主要队列.所以 UIPageViewController 发出尖叫并给出断言失败的原因,无论是当我最初尝试在 setViewControllers animation:YES 的完成块中调用 setViewControllers animation:NO 时,还是现在我只是使用 UINavigationController 来推送一个新的 UIPageViewController(但在 setViewControllers animation:YES 的完成块中再次这样做)是因为这一切都发生在该辅助队列上.

What I have never seen particularly documented, but must now assume to be the case and read up on, is that the completion block for an animation is performed on a secondary queue, not the main one. So the reason why UIPageViewController was squawking and giving assertion failures, both when I originally attempted to call setViewControllers animated:NO in the completion block of setViewControllers animated:YES and also now that I am simply using a UINavigationController to push on a new UIPageViewController (but doing it, again, in the completion block of setViewControllers animated:YES) is because it's all happening on that secondary queue.

这就是上面那段代码完美运行的原因,因为您来自动画完成块并将其发送回主队列,这样您就不会与 UIKit 交叉流.太棒了.

That's why that piece of code up there works perfectly, because you come from the animation completion block and send it back over to the main queue so you don't cross the streams with UIKit. Brilliant.

无论如何,想分享这个旅程,以防有人遇到这个问题.

Anyway, wanted to share this journey, in case anyone runs across this problem.

Swift 版本这里,如果有人感兴趣的话.

Swift version here, if anyone's interested.

这篇关于从 UIPageViewController 中删除视图控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆