如果您拖动UIViewController
以开始UINavigationController
内的互动式广告投放转换,则当前版本下方的UIViewController
会调用viewWillAppear:
,然后是{{ 1}}方法UINavigationControllerDelegate
如果取消转换,则会按预期在顶视图控制器上调用navigationController:willShowViewController:animated:
和viewWillAppear:
。
但是,根本没有调用任何委托方法viewDidAppear:
或navigationController:willShowViewController:animated:
。
考虑到调用UIViewController视图生命周期方法,似乎至少应调用其中一个或两个。我想知道这是故意还是navigationController:didShowViewController:animated:
中的错误。
我真正需要的是能够在我的UINavigationController
子类或UINavigationController
内查看交互式流行音乐的取消时间。有明显的方法吗?
修改
我仍然在寻找解决方案,但我想提一下,我已将此问题报告为Apple的错误。查看文档,没有理由不调用这些委托方法,特别是考虑到调用等效的视图生命周期方法。
EDIT2
我的雷达车票(16823313)今日(2015年5月21日)已关闭并标记为预期。 :(
Engineering已确定此问题的行为符合预期 关于以下信息:
这实际上是正确的行为。导航过渡 发生在B - > A,如果你在转型过程中取消它,你 不会得到didShowViewController:方法。取消这个 转换不应被视为从A - >转换; B因为 你从来没有真正达到过A。
view [Will / Did]出现仍应按预期调用。
这种情况确实很糟糕,因为它违反直觉,但我的答案中的解决方法在可预见的未来应该可以正常工作,至少在我的用例中是这样。
答案 0 :(得分:34)
对于任何有兴趣的人,我找到了两种方法在UINavigationControllerDelegate
级别解决此问题。
使用KVO观察state
的{{1}}属性。不幸的是,取消转换并不会将状态更改为interactivePopGestureRecognizer
,而只是UIGestureRecognizerStateFailed
,因此您需要编写一些额外的代码来跟踪发生的情况,如果您需要识别已取消的或者完成了流行音乐。
测试后,这可能是更好的解决方案:使用UIGestureRecognizerStateEnded
方法向转换协调器添加通知块。它看起来像这样:
navigationController:willShowViewController:animated:
我最初对使用此解决方案犹豫不决,因为文档不清楚是否可以设置多个这些(因为在这种情况下,如果一个未知的视图控制器也设置了自己的通知块,它可能会要么替换这个,要么替换这个。经过测试后,看起来它不是1:1的关系,你可以安全地添加多个通知块。
修改强>
我编辑了上面的代码,将- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
[[self transitionCoordinator] notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> context)
{
if([context isCancelled])
{
UIViewController *fromViewController = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
[self navigationController:navigationController willShowViewController:fromViewController animated:animated];
if([self respondsToSelector:@selector(navigationController:didShowViewController:animated:)])
{
NSTimeInterval animationCompletion = [context transitionDuration] * (double)[context percentComplete];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((uint64_t)animationCompletion * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self navigationController:navigationController didShowViewController:fromViewController animated:animated];
});
}
}
}];
}
调用延迟到仅在完成动画时调用,以更接近地匹配预期的默认行为。
答案 1 :(得分:3)
斯威夫特3:
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
transitionCoordinator?.notifyWhenInteractionEnds { context in
guard context.isCancelled, let fromViewController = context.viewController(forKey: UITransitionContextViewControllerKey.from) else { return }
self.navigationController(self, willShow: fromViewController, animated: animated)
let animationCompletion: TimeInterval = context.transitionDuration * Double(context.percentComplete)
DispatchQueue.main.asyncAfter(deadline: .now() + animationCompletion) {
self.navigationController(self, didShow: fromViewController, animated: animated)
}
}
}
答案 2 :(得分:0)
我将@ Dima&#39; s answer翻译成Swift用于我的项目:
func navigationController(navigationController: UINavigationController, willShowViewController viewController: UIViewController, animated: Bool) {
transitionCoordinator()?.notifyWhenInteractionEndsUsingBlock { context in
guard context.isCancelled(), let fromViewController = context.viewControllerForKey(UITransitionContextFromViewControllerKey) else { return }
self.navigationController(self, willShowViewController: fromViewController, animated: animated)
let animationCompletion: NSTimeInterval = context.transitionDuration() * Double(context.percentComplete())
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
self.navigationController(self, didShowViewController: fromViewController, animated: animated)
}
}
/* Your normal behavior goes here */
}
请注意,我没有检查是否存在navigationController(_:didShowViewController:animated:)
的实现,虽然我相信在编译时会在Swift中检查这一点,并且如果在编译时出现编译错误,你试图在没有实现的情况下调用它。