When I navigate through UIPageViewController
faster than its transition animation I am getting 'Unbalanced calls to begin/end appearance transitions for <MyDataViewController>
' and one of the two views in landscape isn't shown until I try to turn the page.
Anybody has an idea to solve this bug?
Solved following these steps:
1- Declare a flag to indicate that the animation has finished or not:
BOOL pageAnimationFinished;
2- Set this flag to true in viewDidLoad:
pageAnimationFinished = YES;
3- Disable tapGesture for the pageViewController and assign 'self' to panGestureRecognizer delegate:
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- Allow/Disallow panGestureRecognizer through the following gesture recognizer delegate method:
-(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- Add the following pageViewController delegate method:
- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
{
pageAnimationFinished = YES;
}
The above answers were right, but I think more elaborate than needed, and cookbook is helpful. So here is what seems to be working for me:
In the view controller that sets up and calls the pageViewController, declare:
@property (assign) BOOL pageIsAnimating;
and in viewDidLoad:
pageIsAnimating = NO;
add this:
- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers {
pageIsAnimating = YES;
}
and add a couple of lines to:
- (void)pageViewController:(UIPageViewController *)pageViewController
didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers
transitionCompleted:(BOOL)completed {
if (completed || finished) // Turn is either finished or aborted
pageIsAnimating = NO;
...
}
The gestures are suppressed by declining to provide view controller information:
- (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;
}
Oh, and orientation changes reset the flag:
- (UIPageViewControllerSpineLocation)pageViewController:(UIPageViewController *)pageViewController
spineLocationForInterfaceOrientation:(UIInterfaceOrientation)orientation {
pageIsAnimating = NO;
...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With