Jak „anulować” wyświetlanie przejść wyglądu dla niestandardowych przejść kontrolera kontenera
Stworzyłem niestandardowy kontroler kontenera, który działa podobnie do aUIPageViewController
abym mógł zaimplementować niektóre niestandardowe przejścia i logikę źródła danych. Starałem się naśladować sposób, w jaki nowe interfejsy API zmiany kontrolera widoku klienta działają w systemie iOS 7, i działa dobrze, z wyjątkiem niektórych irytujących dziwactw z wywołaniami zwrotów wyglądu podczas przejściaanulowany...
beginAppearanceTransition:animated:
iendAppearanceTransition
być wezwanym?Moja niestandardowa klasa kontenera ma taki kod:
- (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];
}
}
Więc jeśli zadzwonięendAppearanceTransition
niezależnie od tego, czy przejście zostało anulowane, moje wywołania zwrotne widoku wyglądają następująco, gdy przejście zostanie anulowane:
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.
Jeśli zadzwonięendAppearanceTransition
tylko kiedy przejście zakończy się pomyślnie, na początku wszystko wygląda lepiej:
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)
Ale kiedy następnym razem rozpocznę przejście, otrzymambez wywołań zwrotnych wyglądu. Następny zestaw wywołań zwrotnych wyglądu pojawia się dopiero pobeginAppearanceTransition:animated:
po którym następujeendApperanceTransition
połączenie. Warto zauważyć, że janie otrzymuj często zgłaszane „Niesymetryczne wywołania przejść do wyglądu początku / końca dla ViewController„ostrzeżenie konsoli.
WWWDC 2013 Session 218 (Niestandardowe przejścia przy użyciu kontrolerów widoku) Bruce Nilo żartuje sobie z tego, że koledzy mu to mówiąviewWillAppear:
& viewWillDisappear:
naprawdę powinno się nazywaćviewMightAppear:
& viewMightDisappear:
(zobacz sekcję tej sesji rozpoczynającą się o 42:00). Biorąc pod uwagę, że jesteśmy teraz w sferze anulowalnych interaktywnych gestów, wydaje się, że potrzebujemycancelAppearanceTransition
(lubendAppearanceTransition:(BOOL)finished
) metoda dla kontenerów niestandardowych.