UINavigationController自定义交互式转换嵌套的推送动画可能导致导航栏损坏

时间:2014-02-19 18:44:46

标签: objective-c uiviewcontroller uinavigationcontroller uiviewanimation uiviewanimationtransition

我正在实现一个自定义交互式导航控制器转换,通过向下平移导航控制器的视图来“推”一个新的视图控制器。

一切都很好,除了在(努力打破应用程序)的情况下,我再次在导航控制器的视图上向下平移以启动视图控制器的新交互式推送。如果我在完成前一个之后快速完成,我会收到警告

“嵌套推送动画可导致导航栏损坏”

最后,当我继续使用该应用时,我会得到:

在意外状态下完成导航转换。导航栏子视图树可能已损坏。

我理解无论出于何种原因,上下文都没有恢复到正确的状态,并且在推送的控制器的viewDidAppear / viewWillAppear方法中可能会发生一些奇怪的事情,但我无法缩小准确停止的位置在确保最后一个视图控制器已完成推送之前推送新的视图控制器。

我已经使用过渡协调器的notifyWhenInteractionEndsUsingBlock,通过禁用平移手势直到调用此块,但这对我没有帮助。

我在SO上搜索过这些警告,但它似乎并不适用于我的情况 - 而我觉得它与上下文无法正确管理有关。

以下是我正在使用的代码:

我通过将视图控制器推入堆栈来设置委托来处理平移手势的开始状态:

Application.h

-(void)transitionManagerDidBeginDraggingDown:(TransitionManager *)transitionManager{
    MenuViewController *menu = [[MenuViewController alloc] initWithNibName:@"MenuViewController" bundle:nil];
    [self.navigationController pushViewController:menu animated:YES];
}

下面的方法是启动委托将视图控制器推送到堆栈的方法:

TransitionManage.h

- (void)panned:(UIPanGestureRecognizer*)gesture{

    UIViewController *toVc = [self.context viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController *fromVc = [self.context viewControllerForKey:UITransitionContextFromViewControllerKey];

    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:{

            if (self.interactiveTransitionUnderway == NO) {
                self.interactive = YES;

                CGPoint velocity = [gesture velocityInView:gesture.view];
                if (velocity.y < 0) {           // we are pulling upwards on the visible view
                    self.presenting = YES;
                    [self.delegate transitionManagerDidBeginDraggingUp:self];
                }
                else{           // we are pulling downwards on the visible view
                    self.presenting = NO;
                    [self.delegate transitionManagerDidBeginDraggingDown:self];
                }
            }
            break;
        }

        case UIGestureRecognizerStateChanged:{
            CGPoint touchLocation = [gesture locationInView:gesture.view];
            CGPoint translation = [gesture translationInView:gesture.view];

            CGPoint updatedCenter = CGPointMake(self.beginPoint.x, self.beginPoint.y + translation.y);
            toVc.view.center = updatedCenter;
            CGFloat d = fabs(touchLocation.y / CGRectGetHeight(self.parentViewController.view.bounds)) ;

            [self.context updateInteractiveTransition:d];
            break;
        }

        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:{

            CGPoint velocity = [gesture velocityInView:gesture.view];
            CGRect frame;

            if (velocity.y < 0)
                frame = CGRectMake(0, -toVc.view.frame.size.height, toVc.view.frame.size.width, toVc.view.frame.size.height); // pulling up
            else
                frame = CGRectMake(0, 0, toVc.view.frame.size.width, toVc.view.frame.size.height);                            // pulling down

            [UIView animateWithDuration:0.75 delay:0.0 usingSpringWithDamping:0.8 initialSpringVelocity:0.0
                                options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut animations:^{
                                    toVc.view.frame = frame;
                                } completion:^(BOOL finished) {
                                    if (velocity.y < 0){
                                        [self cancelInteractiveTransition];
                                    }
                                    else{
                                        [self finishInteractiveTransition];
                                        UIView *snapshotView = [fromVc.view snapshotViewAfterScreenUpdates:YES];
                                        [toVc.view addSubview:snapshotView];
                                        [toVc.view sendSubviewToBack:snapshotView];
                                    }
                                    [self completeTransition];
                                }];
            break;
        }
        default:
            break;
    }
}

- (void)completeTransition{
    BOOL finished = ![self.context transitionWasCancelled];
    [self.context completeTransition:finished];
}


- (void)animationEnded:(BOOL)transitionCompleted {
    // Reset to our default state
    self.interactive = NO;
    self.presenting = NO;
    self.context = nil;
    self.interactiveTransitionUnderway = NO;
}

1 个答案:

答案 0 :(得分:0)

我对你的问题没有完整的答案,但至少你应该阻止你的代码在完全推送前一个视图控制器(动画完成)之前推动带有动画的新视图控制器。