UIPageViewController transition 'Unbalanced calls to begin/end appearance transitions for '

前端 未结 10 1493
一生所求
一生所求 2021-02-01 20:10

When I navigate through UIPageViewController faster than its transition animation I am getting \'Unbalanced calls to begin/end appearance transitions for <

相关标签:
10条回答
  • 2021-02-01 21:08

    Here's a QUICK version using the delegate:

    add this code (make sure you're including the UIPageViewControllerDelegate in your header or class extension, and assign 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;
    }
    

    then check self.pageAnimationFinished and return nil if it's == NO.

    Longer Explanation:

    - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
    

    We can use this delegate method from UIPageViewControllerDelegate to know when the animation from flipping or swiping through pages finishes. Using this we just can implement it like this:

    - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed {
        pageAnimationFinished = YES;
    }
    

    then, just return nil in your

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

    and

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

    when

    pageAnimationFinished == NO. Be sure to set pageAnimationFinished to NO when you animate. The best way to know when you animate is by using the opposite of

    - (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished previousViewControllers:(NSArray *)previousViewControllers transitionCompleted:(BOOL)completed
    

    namely:

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

    I haven't seen that warning ever since and this can be done in 1/3 of the lines as the other solutions. And it's MUCH easier to follow.

    0 讨论(0)
  • 2021-02-01 21:11

    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;
        ...
    }
    
    0 讨论(0)
  • 2021-02-01 21:11

    Here's the Swift version of Bill Cheswick's answer (currently the top answer):

    Add a variable to hold the current state:

    var pageIsAnimating = false
    

    Set the animating state:

    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
        }
    }
    

    Block the transitions if it's currently animating:

    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
    }
    

    Thank you Bill Cheswick!

    0 讨论(0)
  • 2021-02-01 21:12

    Make use of your UIPageViewControllerDelegate methods and set up guards to prevent creating new page views when excessive page turns are detected.

    1. You can disable gesture recognizers
    2. Set "userInteraction" to disabled on the UIView
    3. maintain a flag on the UIPageViewController to ignore further input when there is an animation occuring. (warning about this option.. ios5 and ios6 have different ways of determining when the animation started..)
    0 讨论(0)
提交回复
热议问题