UIPageViewController转换'非平衡调用开始/结束外观转换为'
当我通过UIPageViewController
比它的转换animation更快地导航时,我得到了“ Unbalanced calls to begin/end appearance transitions for <MyDataViewController>
的Unbalanced calls to begin/end appearance transitions for <MyDataViewController>
”,并且直到我尝试翻页为止, Unbalanced calls to begin/end appearance transitions for <MyDataViewController>
中的两个视图之一才显示出来。
任何人有解决这个错误的想法?
上面的答案是对的,但是我认为比所需要的更详细,而且食谱是有帮助的。 所以这里似乎是为我工作:
在设置和调用pageViewController的视图控制器中,声明:
@property (assign) BOOL pageIsAnimating;
并在viewDidLoad:
pageIsAnimating = NO;
添加这个:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers { pageIsAnimating = YES; }
并添加几行:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { if (completed || finished) // Turn is either finished or aborted pageIsAnimating = NO; ... }
通过拒绝提供视图控制器信息来抑制手势:
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController { if (pageIsAnimating) return nil; ... return after; } - (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController { if (pageIsAnimating) return nil; ... return before; }
哦,方向改变重置标志:
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation { pageIsAnimating = NO; ... }
解决以下步骤:
1-声明一个标志来表示animation已经完成或没有完成:
BOOL pageAnimationFinished;
2-在viewDidLoad中将此标志设置为true:
pageAnimationFinished = YES;
3-为pageViewController禁用tapGesture并将“self”分配给panGestureRecognizer委托:
for (UIGestureRecognizer * gesRecog in self.pageViewController.gestureRecognizers) { if ([gesRecog isKindOfClass:[UITapGestureRecognizer class]]) gesRecog.enabled = NO; else if ([gesRecog isKindOfClass:[UIPanGestureRecognizer class]]) gesRecog.delegate = self; }
4-通过以下手势识别器委托方法允许/禁止panGestureRecognizer:
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ([gestureRecognizer.view isEqual:self.view] || [gestureRecognizer.view isEqual:self.pageViewController.view])) { UIPanGestureRecognizer * panGes = (UIPanGestureRecognizer *)gestureRecognizer; if(!pageAnimationFinished || (currentPage < minimumPage && [panGes velocityInView:self.view].x < 0) || (currentPage > maximumPage && [panGes velocityInView:self.view].x > 0)) return NO; pageAnimationFinished = NO; } return YES; }
5-添加下面的pageViewController委托方法:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { pageAnimationFinished = YES; }
来自Basem Saadawy的良好回答 ,但它有一些缺陷。
其实代表的gestureRecognizerShouldBegin:可以被调用,没有进一步的animation开始。 如果通过垂直手指的移动开始手势,并且水平偏移不足以启动animation(但足以启动gestureRecognizerShouldBegin:),则可以这样做 。 因此,我们的variablespageAnimationFinished将被设置为NO没有实际的animation。 因此, pageViewController:didFinishAnimating:将永远不会被调用,并且您将冻结当前页面而无法更改它。
这就是为什么把NO赋给这个variables的一个更好的地方是一个手势识别器的动作方法,检查它的速度和转换(我们只对水平方向感兴趣)。
所以最后的步骤是:
1)声明一个实例variables(一个标志):
BOOL pageAnimationFinished;
2)设置其初始值
- (void)viewDidLoad { [super viewDidLoad]; ... pageAnimationFinished = YES; }
3)为平移手势识别器分配委托和自定义操作
for (UIGestureRecognizer * gesRecog in self.pageViewController.gestureRecognizers) { if ([gesRecog isKindOfClass:[UIPanGestureRecognizer class]]) { gesRecog.delegate = self; [gr addTarget:self action:@selector(handlePan:)]; } }
3')当手势的平移水平方向较大,手指水平移动时,真正开始animation。
我猜在UIPageViewController分配的内部识别器的动作中使用了相同的逻辑。
- (void) handlePan:(UIPanGestureRecognizer *)gestureRecognizer { if (pageAnimationFinished && gestureRecognizer.state == UIGestureRecognizerStateChanged) { CGPoint vel = [gestureRecognizer velocityInView:self.view]; CGPoint tr = [gestureRecognizer translationInView:self.view]; if (ABS(vel.x) > ABS(vel.y) && ABS(tr.x) > ABS(tr.y)) pageAnimationFinished = NO; // correct place } }
4)如果animation未完成,则禁止手势。
-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && ([gestureRecognizer.view isEqual:self.view] || [gestureRecognizer.view isEqual:self.pageViewController.view])) { UIPanGestureRecognizer * panGes = (UIPanGestureRecognizer *)gestureRecognizer; if(!pageAnimationFinished || (currentPage < minimumPage && [panGes velocityInView:self.view].x < 0) || (currentPage > maximumPage && [panGes velocityInView:self.view].x > 0)) return NO; } return YES; }
5)animation完成
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { pageAnimationFinished = YES; }
我玩得太多了,似乎这是一个很好的解决scheme,效果很好。
以下是使用委托的QUICK版本:
添加这段代码(确保你的头文件或类扩展中包含了UIPageViewControllerDelegate,并赋值self.pageViewController.delegate = self;
):
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers { self.pageAnimationFinished = NO; } - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { self.pageAnimationFinished = YES; }
然后检查self.pageAnimationFinished
并返回nil,如果它是== NO
。
较长的说明:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
我们可以使用UIPageViewControllerDelegate
这个委托方法来知道从页面翻转或者滑动完成的animation何时完成。 使用这个我们可以像这样实现它:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed { pageAnimationFinished = YES; }
那么,只需返回nil
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(PageViewController *)viewController
和
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(PageViewController *)viewController
什么时候
pageAnimationFinished == NO
。 animation时一定要将pageAnimationFinished
设置为NO
。 知道何时使用animation的最好方法是使用相反的方法
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
即:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers
从那以后,我一直没有看到这种警告,这可以用其他解决scheme的三分之一来完成。 而且更容易遵循。
Bill Cheswick的答案的Swift版本(现在是最高的答案):
添加一个variables来保持当前状态:
var pageIsAnimating = false
设置animation状态:
func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [UIViewController]) { self.pageIsAnimating = true } func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { if finished || completed { self.pageIsAnimating = false } }
如果目前正在进行animation制作,则阻止转场:
func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? { if self.pageIsAnimating { return nil } // Your code here } func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? { if self.pageIsAnimating { return nil } // Your code here }
谢谢Bill Cheswick!
我的解决scheme迅速,简单,有效:
- 将pageviewcontroller委托设置为您的类
-
添加下面的代码
extension MyPageVC: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { self.view.isUserInteractionEnabled = false } func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { self.view.isUserInteractionEnabled = true } }
这个怎么样:
- (void)pageViewController:(UIPageViewController*)pgVC willTransitionToViewControllers:(NSArray*)pendingVCs { pgVC.dataSource = nil; // ... to disallow user to change pages until animation completes } - (void)pageViewController:(UIPageViewController*)pgVC didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray*)prevVCs transitionCompleted:(BOOL)completed { if(completed || finished) { pgVC.dataSource = _pgViewDataSource; // ... to allow user to change pages again } }
利用你的UIPageViewControllerDelegate方法并设置警戒,防止在检测到过多的页面转动时创build新的页面视图。
- 您可以禁用手势识别器
- 将“userInteraction”设置为在UIView上禁用
- 在UIPageViewController上维护一个标志,以便在出现animation时忽略进一步的input。 (关于这个选项的警告.. ios5和ios6有不同的方式来确定何时animation开始..)
我不得不把它添加到viewDidAppear:使其工作
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; self.pageAnimationFinished = YES; }
我将尝试在转换时忽略UIPageViewControllers上的手势。
- UIImageView旋转animation在触摸的方向
- 在从UITableView到UIView的交互式转换中animation子视图
- 转换行为使用transitionFromView和transitionWithView
- iOS:有关GLKMatrix4MakeLookAt结果内相机信息的问题
- ios ipad:在横向模式下将TabBar旋转到左侧,并进行变换和约束更新
- iOS – 这个UIPageViewController由UISegmentedControl控制,或者这是什么?
- 将转换应用于UITextView – 防止内容大小调整
- 如何使用UICollectionViewTransitionLayout插入自定义的UICollectionViewLayoutAttributes属性
- 如何使用转换来旋转UIView