我创建了一个自定义容器控制器,其工作方式与 a 类似,UIPageViewController
以便我可以实现一些自定义转换和数据源逻辑。我试图模仿新的客户视图控制器转换 API 在 iOS 7 中的工作方式,它运行良好,除了在取消转换时视图外观回调的一些恼人的怪癖......
即,在执行转换时,究竟应该何时调用beginAppearanceTransition:animated:
和?endAppearanceTransition
我的自定义容器类有一些这样的代码:
- (BOOL)shouldAutomaticallyForwardAppearanceMethods
{
return NO; // Since the automatic callbacks are wrong for our custom transition.
}
- (void)startTransition:(CustomTransitionContext *)context
{
// Get reference to the view controllers involved in the transition.
UIViewController *oldVC = [context viewControllerForKey:UITransitionContextFromViewController];
UIViewController *newVC = [context UITransitionContextToViewController];
// Prepare parent/child relationship changes.
[oldVC willMoveToParentViewController:nil];
[self addChildViewController:newVC];
// Begin view appearance transitions.
[oldVC beginAppearanceTransition:NO animated:[context isAnimated]];
[newVC beginAppearanceTransition:YES animated:[context isAnimated]];
// Register a completion handler to run when the context's completeTransition: method is called.
__weak CustomContainerController *weakSelf = self;
context.transitionCompletionHandler = ^(BOOL complete) {
// End appearance transitions here?
[oldVC endAppearanceTransition];
[newVC endAppearanceTransition];
if (complete) {
// Or only if the transition isn't cancelled; here?
[oldVC endAppearanceTransition];
[newVC endAppearanceTransition];
[oldVC removeFromParentViewController];
[newVC didMoveToParentViewController:weakSelf];
} else {
[newVC removeFromParentViewController];
[oldVC didMoveToParentViewController];
}
}
if ([context isInteractive] && [self.transitionController conformsToProtocol:@protocol(UIViewControllerInteractiveTransitioning)]) {
// Start the interactive transition.
[self.transitionController startInteractiveTransition:context];
} else if ([context isAnimated] && [self.transitionController conformsToProtocol:@protocol(UIViewControllerAnimatedTransitioning)]) {
// Start the animated transition.
[self.transitionController animateTransition:context];
} else {
// Just complete the transition.
[context completeTransition:YES];
}
}
因此,如果我endAppearanceTransition
不管转换是否被取消都调用,那么当转换被取消时,我的视图回调看起来像这样:
oldVC viewWillDisappear: // Fine
newVC viewWillAppear: // Fine
// ... some time later transition is cancelled ...
oldVC viewDidDisappear: // Wrong! This view controller's view is staying.
newVC viewDidAppear: // Wrong! The appearance of this view controllers view was cancelled.
如果我endAppearanceTransition
只在转换成功完成时调用,一开始情况会更好:
oldVC viewWillDisappear: // Fine
newVC viewWillAppear: // Fine
// ... some time later transition is cancelled ...
// ... silence. (which is correct - neither view actually appeared or disappeared,
// and I can undo side effects in viewWill(Dis)Appear using the
// transitionCoordinator object)
但是,下次我开始转换时,我没有收到任何视图外观回调。下一组视图外观回调仅在调用之后beginAppearanceTransition:animated:
到达endApperanceTransition
。值得注意的是,我没有收到经常报告的“对 ViewController 的开始/结束外观转换的不平衡调用”控制台警告。
在WWDC 2013 Session 218 (Custom Transitions Using View Controllers)中,Bruce Nilo 开了一个相当中肯的玩笑,说他的同事告诉他viewWillAppear:
&viewWillDisappear:
真的应该被称为viewMightAppear:
& viewMightDisappear:
(参见从 42:00 开始的那个会话部分)。鉴于我们现在处于可取消交互手势的领域,似乎我们需要一个自定义容器的cancelAppearanceTransition
(或endAppearanceTransition:(BOOL)finished
)方法。