iOS 7 仅在某些时候使用自定义交互过渡
Posted
技术标签:
【中文标题】iOS 7 仅在某些时候使用自定义交互过渡【英文标题】:iOS 7 use custom interactive transitions only some of the time 【发布时间】:2013-11-21 06:07:33 【问题描述】:所以我有一个 UINavigationController,控制器 A 作为根控制器。
当我想将控制器 B 推到顶部时,我想使用自定义动画过渡和自定义交互过渡。这很好用。
当我想将控制器 C 推到顶部时,我想退回到 UINavigationController 附带的 默认 推送/弹出转换。为了实现这一点,我为
返回 nilnavigationController:animationControllerForOperation:fromViewController:toViewController:
但是如果你返回 nil,那么
navigationController:interactionControllerForAnimationController:
永远不会被调用,默认的“从左边缘平移”弹出交互过渡不起作用。
有没有办法返回默认的推送/弹出动画控制器和交互控制器?
(id<UIViewControllerAnimatedTransitioning>
和id<UIViewControllerInteractiveTransitioning>
有具体实现吗?)
还是其他方式?
【问题讨论】:
【参考方案1】:您应该将 NavigationController 的 interactivePopGestureRecognizer 委托设置为 self,然后在 -gestureRecognizerShouldBegin 中处理其行为:
也就是说,当您想要触发内置弹出手势时,您必须从此方法返回 YES。您的自定义手势也是如此 - 您必须弄清楚您正在处理的识别器。
- (void)setup
self.interactiveGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleTransitionGesture:)];
self.interactiveGestureRecognizer.delegate = self;
[self.navigationController.view addGestureRecognizer:self.interactiveGestureRecognizer];
self.navigationController.interactivePopGestureRecognizer.delegate = self;
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
// Don't handle gestures if navigation controller is still animating a transition
if ([self.navigationController.transitionCoordinator isAnimated])
return NO;
if (self.navigationController.viewControllers.count < 2)
return NO;
UIViewController *fromVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-1];
UIViewController *toVC = self.navigationController.viewControllers[self.navigationController.viewControllers.count-2];
if ([fromVC isKindOfClass:[ViewControllerB class]] && [toVC isKindOfClass:[ViewControllerA class]])
if (gestureRecognizer == self.interactiveGestureRecognizer)
return YES;
else if (gestureRecognizer == self.navigationController.interactivePopGestureRecognizer)
return YES;
return NO;
您可以查看sample project 以了解您的情况。视图控制器 A 和 B 之间的转换是自定义动画,带有自定义 B->A 弹出手势。视图控制器 B 和 C 之间的转换是默认的,带有内置导航控制器的弹出手势。
希望这会有所帮助!
【讨论】:
根据 Apple 的 DTS 人员的说法,UINavigationController 附带的私有 interactivePopGestureRecognizer 在其委托中进行了许多检查,其中一些调用了私有 API。实现自己的委托并不能保证 100% 覆盖所有情况。 @Ziconic 案例?【参考方案2】:您需要在每次演示之前设置委托 - 例如在 prepareForSeque: 中。如果您想要自定义过渡,请将其设置为 self.如果你想要默认转换(如默认弹出转换),请将其设置为 nil。
【讨论】:
遗憾的是,这实际上是 Apple DTS 人员推荐的正确答案和方法,尽管它不是一个特别优雅的方法。基本上,您需要有 2 个 UINavigationControllerDelegate 对象,一个实现转换回调,一个不实现(或为零)。要获得默认的弹出转换,请使用不带回调的委托(或将委托设置为 nil)。要获得自定义转换,请将委托换成具有回调的委托(并在转换完成后恢复原始委托)。 这仍然是推荐的方法吗?【参考方案3】:在每次转换之前/之后设置委托是一种有效的解决方法,但是如果您实现了其他 UINavigationControllerDelegate
的方法并且您需要保留它们,您可以按照 Ziconic 的建议拥有 2 个委托对象或使用 NSObject 的 @ 987654322@。在您的导航委托中,您可以实现:
- (BOOL)respondsToSelector:(SEL)aSelector
if (aSelector == @selector(navigationController:animationControllerForOperation:fromViewController:toViewController:) ||
aSelector == @selector(navigationController:interactionControllerForAnimationController:))
return self.interactivePushTransitionEnabled;
return [super respondsToSelector:aSelector];
然后,您应该确保根据需要更新 interactivePushTransitionEnabled
。在您的示例中,您应该仅在显示控制器 A 时将属性设置为 YES
。
只有一件事要做:强制 UINavigationController 重新评估其委托实现的方法。这可以通过执行以下操作轻松完成:
navigationController.delegate = nil;
navigationController.delegate = self; // or whatever object you use as the delegate
【讨论】:
【参考方案4】:在您完成自定义转换后,尝试将 (self.)navigationController.delegate
设置为 nil
(或将其恢复为以前的值)。
【讨论】:
【参考方案5】:在您的手势识别器中,将委托(对您自己)设置在那里并返回您的动画和交互式过渡。返回交互式过渡时,请务必再次取消设置委托,以便其他所有内容继续使用默认过渡。
我有一个working example on github。
- (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController
// Unset the delegate so that all other types of transitions (back, normal animated push not initiated by a gesture) get the default behavior.
self.navigationController.delegate = nil;
if (self.edgePanGestureRecognizer.state == UIGestureRecognizerStateBegan)
self.percentDrivenInteractiveTransition = [UIPercentDrivenInteractiveTransition new];
else
self.percentDrivenInteractiveTransition = nil;
return self.percentDrivenInteractiveTransition;
【讨论】:
以上是关于iOS 7 仅在某些时候使用自定义交互过渡的主要内容,如果未能解决你的问题,请参考以下文章
使用带有子类 UINavigationController 的自定义 iOS 7 过渡偶尔会导致黑屏