如何“取消”自定义容器控制器转换的视图外观转换 [英] How to 'cancel' view appearance transitions for custom container controller transitions

查看:155
本文介绍了如何“取消”自定义容器控制器转换的视图外观转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个自定义容器控制器,其工作方式类似于 UIPageViewController ,这样我就可以实现一些自定义转换&数据源逻辑。我试图模仿新的客户视图控制器转换API在iOS 7中的工作方式,除了在转换为 取消 ...

I have created a custom container controller that works similarly to a UIPageViewController so that I could implement some custom transitions & data source logic. I tried to mimic the way the new customer view controller transition APIs work in iOS 7, and it works well except for some irritating quirks with the view appearance callbacks when a transition is cancelled...

我的自定义容器类有一些代码如下:

My custom container class has some code like this:

- (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 无论过渡是否被取消,我的视图回调在取消转换时都是这样的:

So if I call endAppearanceTransition regardless of whether the transition was cancelled, then my view callbacks look like this when a transition is cancelled:

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 转换成功后,事情看起来好一点:

If I call endAppearanceTransition only when the transition finished successfully, things look better at first:

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 开始/结束外观转换的不平衡调用控制台警告。

But then, the next time I start a transition, I receive no view appearance callbacks. The next set of view appearance callbacks arrive only after a beginAppearanceTransition:animated: that is followed by an endApperanceTransition call. It is worth noting that I don't receive the oft-reported "Unbalanced calls to begin/end appearance transitions for ViewController" console warning.

WWDC 2013 Session 218(使用视图控制器进行自定义转换)布鲁斯·尼洛(Bruce Nilo)对他的同事们开了一个相当相关的笑话,告诉他 viewWillAppear:& viewWillDisappear:确实应该被称为 viewMightAppear:& viewMightDisappear: (请参阅从42:00开始的该会话部分)。鉴于我们现在处于可取消的交互式手势领域,似乎我们需要 cancelAppearanceTransition (或 endAppearanceTransition:(BOOL)已完成)自定义容器的方法。

In WWDC 2013 Session 218 (Custom Transitions Using View Controllers) Bruce Nilo makes a rather pertinent joke about his colleagues telling him that viewWillAppear: & viewWillDisappear: really ought to be called viewMightAppear: & viewMightDisappear: (see the section of that session beginning at 42:00). Given that we're now in the realm of cancellable interactive gestures, it seems that we need a cancelAppearanceTransition (or endAppearanceTransition:(BOOL)finished) method for custom containers.

推荐答案

因此通常采用SO的方式,你花费数小时毫无工作地处理问题,然后在你发布问题后,你就找到了答案...

So as is often the way with SO, you spend hours fruitlessly working on a problem, and then right after you post the question, you find the answer...

我看了<$ c $的外观回调c> UINavigationController 的内置 interactivePopGestureRecognizer ,看看取消过渡时会发生什么,看来我对外观方法的假设是什么应该被调用错误。

I looked at the appearance callbacks of UINavigationController's built-in interactivePopGestureRecognizer to see what happens when the cancelling the transition, and it appears that my assumption about what appearance methods should be called was wrong.

对于成功转换到的视图控制器,会收到以下回调(正如您所期望的那样):

For a view controller that is successfully transitioned to, the following callbacks are received (as you'd expect):

                 transition
                  finished
viewWillAppear:  ---------->  viewDidAppear:

但是对于不成功的视图控制器转换(即过渡被取消),视图控制器收到以下回调:

But for a view controller transition that is unsuccessful (i.e. the transition was cancelled), the view controller receives the following callbacks:

                 transition                       immediately
                 cancelled                        followed by
viewWillAppear:  ---------->  viewWillDisappear:  ---------->  viewDidDisappear:

所以我们得到了更多那些狡猾的视图外观语义;我不确定视图如何消失如果还没有出现!哦,好吧......我认为它比一个说出现,然后什么都没发生的观点要好一些。

So we get a bit more of those dodgy view appearance semantics; I'm not sure how a view can disappear if it hasn't yet appeared! Oh well... I suppose it's slightly better than a view saying it will appear, and then nothing happening.

所以,回到我的身边 CustomTransitionContext transitionCompletionHandler 代码,解决方案如下所示:

So, returning to my CustomTransitionContext's transitionCompletionHandler code, the solution looks like this:

...

// Register a completion handler to run when the context's completeTransition: method is called.
__weak CustomContainerController *weakSelf = self;
__weak CustomTransitionContext *weakContext = context;
context.transitionCompletionHandler = ^(BOOL complete) {
    if (complete) {
        // End the appearance transitions we began earlier.
        [oldVC endAppearanceTransition];
        [newVC endAppearanceTransition];

        [oldVC removeFromParentViewController];
        [newVC didMoveToParentViewController:weakSelf];
    } else {
        // Before ending each appearance transition, begin an
        // appearance transition in the opposite direction.
        [newVC beginAppearanceTransition:NO animated:[weakContext isAnimated]];
        [newVC endAppearanceTransition];
        [oldVC beginAppearanceTransition:YES animated:[weakContext isAnimated]];
        [oldVC endAppearanceTransition];

        [newVC removeFromParentViewController];
        [oldVC didMoveToParentViewController];
    }
}

....

所以现在外观回调看起来像这样:

So now the appearance callbacks look like this:

oldVC viewWillDisappear:
newVC viewWillAppear:
// ... some time later transition is cancelled ...
newVC viewWillDisappear:
newVC viewDidDisappear:
oldVC viewWillAppear:
oldVC viewDidAppear:

此外,后续转换现在按预期触发回调(因为我们通过调用 endAppearanceTransition关闭所有转换)。

Also, subsequent transitions now trigger the callbacks as expected (since we're closing off all transitions with calls to endAppearanceTransition).

这篇关于如何“取消”自定义容器控制器转换的视图外观转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆