我正在实现自定义的交互式导航控制器转换,以通过向下平移导航控制器的视图来“推”新的视图控制器。UINavigationController自定义交互转换嵌套的推动动画可能导致导航栏损坏
一切都很好,除了在努力打破应用程序的情况下,我在导航控制器的视图上再次平移以启动视图控制器的新交互式推送。如果我刚刚完成一前一后做的不够快,我得到一个警告
“嵌套推动画可以导致损坏的导航栏”
而最终我继续与应用程序打,我将获得:
完成处于意外状态的导航转换。导航栏子视图树可能会损坏。
我明白无论什么原因,上下文没有回到正确的状态,并且在推送的控制器的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;
}